├── .ert-runner ├── .gitignore ├── testing-blog ├── Gemfile ├── org │ ├── img │ │ └── plot-sin.png │ ├── about-me.org │ ├── contact.org │ ├── interesting-post.org │ ├── about.org │ └── blogging-with-org2jekyll.org ├── .gitignore ├── assets │ └── img │ │ └── plot-sin.png ├── index.markdown ├── about-me.html ├── contact.html ├── 404.html ├── about.html ├── _posts │ ├── 2020-05-27-interesting-post.html │ ├── 2020-05-09-welcome-to-jekyll.markdown │ └── 2020-05-09-blogging-with-org2jekyll.html ├── _config.yml ├── testing-blog-config.el ├── Gemfile.lock └── gemset.nix ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── Cask ├── release.sh ├── README-dev.org ├── shell.nix ├── .travis.yml ├── Makefile ├── test ├── test-helper.el ├── org2jekyll-utilities-test.el └── org2jekyll-test.el ├── org2jekyll-utilities.el ├── flake.nix ├── flake.lock ├── todo.org ├── README.org ├── LICENSE └── org2jekyll.el /.ert-runner: -------------------------------------------------------------------------------- 1 | -L . 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.cask/ 2 | /dist/ 3 | /gems/ 4 | /result 5 | -------------------------------------------------------------------------------- /testing-blog/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages', group: :jekyll_plugins 3 | -------------------------------------------------------------------------------- /testing-blog/org/img/plot-sin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ardumont/org2jekyll/HEAD/testing-blog/org/img/plot-sin.png -------------------------------------------------------------------------------- /testing-blog/.gitignore: -------------------------------------------------------------------------------- 1 | gems/ 2 | _site 3 | .sass-cache 4 | .jekyll-cache 5 | .jekyll-metadata 6 | vendor 7 | *~ 8 | *.*~ 9 | -------------------------------------------------------------------------------- /testing-blog/assets/img/plot-sin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ardumont/org2jekyll/HEAD/testing-blog/assets/img/plot-sin.png -------------------------------------------------------------------------------- /testing-blog/index.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | # Feel free to add content and custom Front Matter to this file. 3 | # To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults 4 | 5 | layout: home 6 | --- 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Hello, 2 | 3 | Can you please provide the following information? 4 | Thanks in advance 5 | 6 | ### Rapid summary 7 | 8 | ### What issue does this fix or improve? 9 | 10 | ### Have you checked and/or added tests? 11 | 12 | Cheers, 13 | -------------------------------------------------------------------------------- /testing-blog/about-me.html: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-05-09 13:43:00 3 | tags: 4 | - about 5 | - me 6 | author: drjekyll&mrtony 7 | layout: page 8 | title: About me 9 | excerpt: About me page 10 | categories: 11 | - about 12 | - me 13 | permalink: /about-me/ 14 | --- 15 |

16 | About me stuff… 17 |

18 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source gnu) 2 | (source melpa) 3 | 4 | (package-file "org2jekyll.el") 5 | 6 | (files "org2jekyll.el" 7 | "README.org") 8 | 9 | (development 10 | (depends-on "undercover") 11 | (depends-on "ert-runner") 12 | (depends-on "ert") 13 | (depends-on "ert-expectations") 14 | (depends-on "el-mock")) 15 | -------------------------------------------------------------------------------- /testing-blog/contact.html: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-05-09 17:59:00 3 | tags: 4 | - contact 5 | author: drjekyll&mrtony 6 | layout: page 7 | title: Contact us 8 | excerpt: A page to describe how to get in touch 9 | categories: 10 | - contact 11 | permalink: /about/ 12 | --- 13 |

14 | Here is how to get in touch, open issues or PRs. 15 | Collaboration is the key! 16 |

17 | -------------------------------------------------------------------------------- /testing-blog/org/about-me.org: -------------------------------------------------------------------------------- 1 | #+STARTUP: showall 2 | #+STARTUP: hidestars 3 | #+OPTIONS: H:2 num:nil tags:nil toc:nil timestamps:t 4 | #+LAYOUT: page 5 | #+AUTHOR: drjekyll&mrtony 6 | #+DATE: 2020-05-09 Sat 13:43 7 | #+TITLE: About me 8 | #+DESCRIPTION: About me page 9 | #+TAGS: about, me 10 | #+CATEGORIES: about, me 11 | #+PERMALINK: /about-me/ 12 | 13 | About me stuff... 14 | -------------------------------------------------------------------------------- /testing-blog/org/contact.org: -------------------------------------------------------------------------------- 1 | #+STARTUP: showall 2 | #+STARTUP: hidestars 3 | #+OPTIONS: H:2 num:nil tags:nil toc:nil timestamps:t 4 | #+LAYOUT: page 5 | #+AUTHOR: drjekyll&mrtony 6 | #+DATE: 2020-05-09 Sat 17:59 7 | #+TITLE: Contact us 8 | #+DESCRIPTION: A page to describe how to get in touch 9 | #+TAGS: contact 10 | #+CATEGORIES: contact 11 | 12 | Here is how to get in touch, open issues or PRs. 13 | Collaboration is the key! 14 | -------------------------------------------------------------------------------- /testing-blog/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page not found :(

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -ne 2 ]; then 4 | cat <" 6 | - VERSION version to release (0.1.6 for example) 7 | - PACKAGE package to release 8 | 9 | To install the token, execute the install-marmalade-token.sh. 10 | EOF 11 | exit 1; 12 | fi 13 | VERSION=$1 14 | PACKAGE=$2 15 | 16 | WDIR=$(dirname $0) 17 | 18 | # launched from the current dev branch 19 | 20 | git fetch -p --all 21 | 22 | git checkout master 23 | 24 | git merge origin/master 25 | 26 | git tag -a -s $VERSION 27 | 28 | git push origin --tag 29 | 30 | make package 31 | -------------------------------------------------------------------------------- /README-dev.org: -------------------------------------------------------------------------------- 1 | #+title: README-dev 2 | #+author: ardumont 3 | 4 | * Enter the nix develop (requires flake) 5 | 6 | #+BEGIN_SRC sh 7 | nix develop 8 | #+END_SRC 9 | 10 | * Run tests 11 | 12 | #+BEGIN_SRC sh 13 | make test 14 | #+END_SRC 15 | 16 | * Run jekyll instance 17 | 18 | #+BEGIN_SRC sh 19 | make run-dev 20 | #+END_SRC 21 | 22 | * Run an emacs and play with the sandbox 23 | 24 | #+BEGIN_SRC sh 25 | make run-emacs 26 | #+END_SRC 27 | 28 | You now have an emacs ready with the latest: 29 | - org2jekyll 30 | - testing-blog sandbox configuration 31 | 32 | 33 | Then play: M-x org2jekyll- 34 | 35 | -------------------------------------------------------------------------------- /testing-blog/org/interesting-post.org: -------------------------------------------------------------------------------- 1 | #+STARTUP: hidestars 2 | #+OPTIONS: H:2 num:t tags:t toc:t timestamps:t 3 | #+LAYOUT: post 4 | #+AUTHOR: drjekyll&mrtony 5 | #+DATE: 2020-05-27 Wed 18:18 6 | #+TITLE: Interesting scratch post 7 | #+DESCRIPTION: An interesting post about something 8 | #+TAGS: hi hooooooo 9 | #+CATEGORIES: category 10 | 11 | In [[local:/blogging-with-org2jekyll-setup][this post]], we saw that interesting property. Now, here goes another part 12 | which is even more so. 13 | 14 | * title 15 | 16 | ** chapter 17 | 18 | * another title 19 | 20 | #+BEGIN_SRC sh 21 | echo this is now 22 | #+END_SRC 23 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | 3 | let org2jekyll-emacs = pkgs.emacsWithPackages (epkgs: 4 | (with epkgs.melpaStablePackages; [ 5 | pkgs.org2jekyll 6 | dash 7 | s 8 | htmlize 9 | ])); 10 | in pkgs.stdenv.mkDerivation { 11 | name = "org2jekyll-env"; 12 | buildInputs = with pkgs; [ 13 | org2jekyll-emacs 14 | # emacs-lisp testing 15 | cask 16 | # jekyll instance to check manually against 17 | zlib 18 | ruby 19 | jekyll 20 | bundler 21 | bundix 22 | gitAndTools.gitFull 23 | ]; 24 | # GEM_HOME = "./gems"; # Do not install gems in user's home (default behavior) 25 | BUNDLE_PATH = "../gems"; 26 | BUNDLE_DISABLE_SHARED_GEMS = 1; 27 | src = null; 28 | } 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Use nix-emacs-ci for travis CI 3 | # URL: https://github.com/purcell/nix-emacs-ci 4 | # 5 | 6 | language: nix 7 | 8 | os: 9 | - linux 10 | 11 | env: 12 | - EMACS_CI=emacs-26-1 13 | - EMACS_CI=emacs-26-2 14 | - EMACS_CI=emacs-26-3 15 | 16 | install: 17 | # The default "emacs" executable on the $PATH will now be the version named by $EMACS_CI 18 | - bash <(curl https://raw.githubusercontent.com/purcell/nix-emacs-ci/master/travis-install) 19 | # enforce the stable channel version 20 | - nix-channel --add https://nixos.org/channels/nixos-20.03 nixpkgs-stable 21 | - nix-channel --update nixpkgs-stable 22 | - nix-channel --list 23 | - nix-env -iA nixpkgs-stable.cask 24 | 25 | script: 26 | - make install test 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Hello, 2 | 3 | Can you please provide the following information? 4 | 5 | Thanks in advance. 6 | 7 | ## bug? 8 | 9 | ### M-x org2jekyll-bug-report 10 | 11 | Report back the output from that command here. 12 | (You can quote it with ``` for a better readability). 13 | 14 | ### Expected behavior 15 | 16 | What command did you use and what were you expecting? 17 | 18 | ### Actual behavior 19 | 20 | What really happened? 21 | 22 | ### Steps to reproduce the behavior 23 | 24 | How can we try and reproduce? 25 | 26 | Please your [org2jekyll configuration](https://github.com/ardumont/org2jekyll#setup). 27 | And the *Compile-Log* buffer when it's some suspected packaging problem... 28 | 29 | 30 | ## Improvments? 31 | 32 | ### What do you want? 33 | 34 | ### Why is it better? 35 | 36 | Thanks for sharing! 37 | 38 | Cheers, 39 | -------------------------------------------------------------------------------- /testing-blog/org/about.org: -------------------------------------------------------------------------------- 1 | #+STARTUP: showall 2 | #+STARTUP: hidestars 3 | #+OPTIONS: H:2 num:nil tags:nil toc:nil timestamps:t 4 | #+LAYOUT: page 5 | #+AUTHOR: drjekyll&mrtony 6 | #+DATE: 2020-05-09 Sat 13:10 7 | #+TITLE: About 8 | #+DESCRIPTION: About page statically defined, rewritten in org to demonstrate the other default layout 9 | #+TAGS: about 10 | #+CATEGORIES: about 11 | #+PERMALINK: /about/ 12 | 13 | Not original at all, we just plainly rewrote the default templated "about" page 14 | (from the /jekyll new testing-blog/ stanza that initializes jekyll blog site). 15 | 16 | * About 17 | 18 | This is the base Jekyll theme. You can find out more info about customizing 19 | your Jekyll theme, as well as basic Jekyll usage documentation at [[https://jekyllrb.com][jekyllrb.com]]. 20 | 21 | You can find the source code for Minima at GitHub: [[https://github.com/jekyll][jekyll]] / [[https://github.com/jekyll/minima][minima]] 22 | 23 | You can find the source code for Jekyll at GitHub: [[https://github.com/jekyll][jekyll]] / [[https://github.com/jekyll/jekyll][jekyll]] 24 | 25 | -------------------------------------------------------------------------------- /testing-blog/about.html: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-05-09 13:10:00 3 | tags: 4 | - about 5 | author: drjekyll&mrtony 6 | layout: page 7 | title: About 8 | excerpt: About page statically defined, rewritten in org to demonstrate the other default layout 9 | categories: 10 | - about 11 | permalink: /about/ 12 | --- 13 |

14 | Not original at all, we just plainly rewrote the default templated "about" page 15 | (from the jekyll new testing-blog stanza that initializes jekyll blog site). 16 |

17 | 18 |
19 |

About

20 |
21 |

22 | This is the base Jekyll theme. You can find out more info about customizing 23 | your Jekyll theme, as well as basic Jekyll usage documentation at jekyllrb.com. 24 |

25 | 26 |

27 | You can find the source code for Minima at GitHub: jekyll / minima 28 |

29 | 30 |

31 | You can find the source code for Jekyll at GitHub: jekyll / jekyll 32 |

33 |
34 |
35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE = org2jekyll 2 | VERSION = $$(grep "^;; Version: " $(PACKAGE).el | cut -f3 -d' ') 3 | ARCHIVE = $(PACKAGE)-$(VERSION).tar 4 | EMACS ?= emacs 5 | CASK ?= cask 6 | BLOG ?= testing-blog 7 | 8 | activate: 9 | nix develop 10 | 11 | pr: 12 | hub pull-request -b ardumont:master 13 | 14 | .PHONY: clean 15 | 16 | deps: 17 | ${CASK} 18 | 19 | build: 20 | ${CASK} build 21 | 22 | clean-dist: 23 | rm -rf dist/ 24 | 25 | clean: clean-dist 26 | rm -rf *.tar 27 | ${CASK} clean-elc 28 | 29 | install: 30 | ${CASK} install 31 | 32 | test: clean 33 | ${CASK} exec ert-runner 34 | 35 | pkg-el: 36 | ${CASK} package 37 | 38 | package: clean pkg-el 39 | cp dist/$(ARCHIVE) . 40 | make clean-dist 41 | 42 | info: 43 | ${CASK} info 44 | 45 | release: 46 | ./release.sh $(VERSION) $(PACKAGE) 47 | 48 | version: 49 | @echo -e "application $(PACKAGE): $(VERSION)\npackage: $(ARCHIVE)" 50 | 51 | update: 52 | cd $(BLOG) ; bundle update; bundle lock; bundix 53 | 54 | run-dev: 55 | cd $(BLOG); bundle exec jekyll serve --watch --trace 56 | 57 | clean-dev: 58 | cd $(BLOG); bundle exec jekyll clean 59 | 60 | run-emacs: 61 | cd testing-blog && $(EMACS) -Q --load=../org2jekyll.el --load=./testing-blog-config.el \ 62 | --eval="(dired \"./org\")" 63 | -------------------------------------------------------------------------------- /test/test-helper.el: -------------------------------------------------------------------------------- 1 | ;;; test-helper.el --- -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015-2017 Antoine Romain Dumont 4 | 5 | ;; Author: Antoine Romain Dumont 6 | ;; Keywords: 7 | 8 | ;; This program is free software; you can redistribute it and/or modify 9 | ;; it under the terms of the GNU General Public License as published by 10 | ;; the Free Software Foundation, either version 3 of the License, or 11 | ;; (at your option) any later version. 12 | 13 | ;; This program is distributed in the hope that it will be useful, 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ;; GNU General Public License for more details. 17 | 18 | ;; You should have received a copy of the GNU General Public License 19 | ;; along with this program. If not, see . 20 | 21 | ;;; Commentary: 22 | 23 | ;; 24 | 25 | ;;; Code: 26 | 27 | (when (require 'cl-lib 'no-error) 28 | (defalias 'incf 'cl-incf)) 29 | 30 | (require 'undercover) 31 | (undercover "*.el" 32 | (:exclude "*-test.el") 33 | (:report-file "/tmp/undercover-report.json")) 34 | 35 | (require 'org2jekyll) 36 | 37 | ;;; test-helper.el ends here 38 | -------------------------------------------------------------------------------- /testing-blog/_posts/2020-05-27-interesting-post.html: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-05-27 18:18 3 | author: drjekyll&mrtony 4 | layout: post 5 | title: Interesting scratch post 6 | excerpt: An interesting post about something 7 | tags: 8 | - hi 9 | - hooooooo 10 | categories: 11 | - category 12 | --- 13 |
14 |

Table of Contents

15 |
16 | 24 |
25 |
26 |

27 | In this post, we saw that interesting property. Now, here goes another part 28 | which is even more so. 29 |

30 | 31 |
32 |

1 title

33 |
34 |
35 |
36 |

1.1 chapter

37 |
38 |
39 | 40 |
41 |

2 another title

42 |
43 |
44 |
echo this is now
45 | 
46 |
47 |
48 |
49 | -------------------------------------------------------------------------------- /testing-blog/_posts/2020-05-09-welcome-to-jekyll.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Welcome to Jekyll!" 4 | date: 2020-05-09 12:13:01 +0200 5 | categories: jekyll update 6 | --- 7 | You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated. 8 | 9 | Jekyll requires blog post files to be named according to the following format: 10 | 11 | `YEAR-MONTH-DAY-title.MARKUP` 12 | 13 | Where `YEAR` is a four-digit number, `MONTH` and `DAY` are both two-digit numbers, and `MARKUP` is the file extension representing the format used in the file. After that, include the necessary front matter. Take a look at the source for this post to get an idea about how it works. 14 | 15 | Jekyll also offers powerful support for code snippets: 16 | 17 | {% highlight ruby %} 18 | def print_hi(name) 19 | puts "Hi, #{name}" 20 | end 21 | print_hi('Tom') 22 | #=> prints 'Hi, Tom' to STDOUT. 23 | {% endhighlight %} 24 | 25 | Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll Talk][jekyll-talk]. 26 | 27 | [jekyll-docs]: https://jekyllrb.com/docs/home 28 | [jekyll-gh]: https://github.com/jekyll/jekyll 29 | [jekyll-talk]: https://talk.jekyllrb.com/ 30 | -------------------------------------------------------------------------------- /test/org2jekyll-utilities-test.el: -------------------------------------------------------------------------------- 1 | ;;; org2jekyll-utilities-test.el --- -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015-2017 Antoine R. Dumont 4 | 5 | ;; Author: Antoine R. Dumont 6 | ;; Keywords: 7 | 8 | ;; This program is free software; you can redistribute it and/or modify 9 | ;; it under the terms of the GNU General Public License as published by 10 | ;; the Free Software Foundation, either version 3 of the License, or 11 | ;; (at your option) any later version. 12 | 13 | ;; This program is distributed in the hope that it will be useful, 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ;; GNU General Public License for more details. 17 | 18 | ;; You should have received a copy of the GNU General Public License 19 | ;; along with this program. If not, see . 20 | 21 | ;;; Commentary: 22 | 23 | ;; 24 | 25 | ;;; Code: 26 | 27 | (require 'org2jekyll-utilities) 28 | (require 'ert) 29 | 30 | (ert-deftest test-org2jekyll-tests-with-temp-buffer () 31 | (should (string="line 1 32 | line 2 33 | line 3" 34 | (org2jekyll-tests-with-temp-buffer 35 | "line 1 36 | line 2 37 | line 3" 38 | (buffer-substring-no-properties (point-min) (point-max)))))) 39 | 40 | (ert-deftest test-org2jekyll-tests-with-temp-buffer-and-return-buffer-content () 41 | (should (string= "1 42 | 2 43 | 3 44 | " 45 | (org2jekyll-tests-with-temp-buffer-and-return-content 46 | "line 1 47 | line 2 48 | line 3 49 | " 50 | (replace-regexp "line " "" nil (point-min) (point-max)))))) 51 | 52 | 53 | (provide 'org2jekyll-utilities-test) 54 | ;;; org2jekyll-utilities-test.el ends here 55 | -------------------------------------------------------------------------------- /org2jekyll-utilities.el: -------------------------------------------------------------------------------- 1 | ;;; org2jekyll-utilities.el --- -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2015-2017 Antoine R. Dumont 4 | 5 | ;; Author: Antoine R. Dumont 6 | ;; Keywords: 7 | 8 | ;; This program is free software; you can redistribute it and/or modify 9 | ;; it under the terms of the GNU General Public License as published by 10 | ;; the Free Software Foundation, either version 3 of the License, or 11 | ;; (at your option) any later version. 12 | 13 | ;; This program is distributed in the hope that it will be useful, 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ;; GNU General Public License for more details. 17 | 18 | ;; You should have received a copy of the GNU General Public License 19 | ;; along with this program. If not, see . 20 | 21 | ;;; Commentary: 22 | 23 | ;; 24 | 25 | ;;; Code: 26 | 27 | (defmacro org2jekyll-tests-with-temp-buffer (text body-test) 28 | "A `org-mode' mode buffer helper test on buffer. 29 | TEXT is the content of the buffer. 30 | BODY-TEST is the assertion to test on the buffer. 31 | NB-LINES-FORWARD is the number of lines to get back to." 32 | `(with-temp-buffer 33 | (org-mode) 34 | (org2jekyll-mode) 35 | (insert ,text) 36 | ,body-test)) 37 | 38 | (defmacro org2jekyll-tests-with-temp-buffer-and-return-content (text body-test) 39 | "A `org-mode' mode buffer helper test on buffer. 40 | TEXT is the content of the buffer. 41 | BODY-TEST is the assertion to test on the buffer. 42 | NB-LINES-FORWARD is the number of lines to get back to." 43 | `(with-temp-buffer 44 | (org-mode) 45 | (org2jekyll-mode) 46 | (insert ,text) 47 | ,body-test 48 | (buffer-substring-no-properties (point-min) (point-max)))) 49 | 50 | (provide 'org2jekyll-utilities) 51 | ;;; org2jekyll-utilities.el ends here 52 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "org2jekyll flake"; 3 | 4 | inputs = { 5 | nixpkgs = { 6 | type = "github"; 7 | owner = "NixOS"; 8 | repo = "nixpkgs"; 9 | ref = "nixpkgs-unstable"; 10 | follows = "nix/nixpkgs"; 11 | }; 12 | 13 | flake-utils = { 14 | type = "github"; 15 | owner = "numtide"; 16 | repo = "flake-utils"; 17 | ref = "master"; 18 | }; 19 | }; 20 | 21 | outputs = { self, nix, nixpkgs, flake-utils, ... }: 22 | flake-utils.lib.eachDefaultSystem 23 | (system: 24 | let lib = nixpkgs.lib; 25 | pkgs = nixpkgs.legacyPackages.${system}; 26 | pname = "org2jekyll"; 27 | version = "0.2.7"; 28 | in rec { 29 | packages."${system}" = rec { 30 | org2jekyll = pkgs.stdenv.mkDerivation { 31 | inherit pname version; 32 | src = ./.; 33 | buildInputs = with pkgs.emacs.pkgs; [ 34 | emacs s dash htmlize 35 | ]; 36 | unpackPhase = '' 37 | cp $src/org2jekyll.el . 38 | ''; 39 | buildPhase = '' 40 | emacs -L . --batch -f batch-byte-compile *.el 41 | ''; 42 | installPhase = 43 | let install-dir = "$out/share/emacs/site-lisp/elpa/${pname}-${version}/"; in 44 | '' 45 | mkdir -p ${install-dir} 46 | cp -v *.el *.elc ${install-dir} 47 | ''; 48 | 49 | doCheck = false; 50 | 51 | meta = { 52 | description = "Minor mode to publish org-mode post to jekyll without specific yaml."; 53 | homepage = https://github.com/ardumont/org2jekyll/; 54 | license = lib.licenses.gpl2; 55 | maintainers = with lib.maintainers; [ ardumont ]; 56 | }; 57 | }; 58 | }; 59 | 60 | devShell = import ./shell.nix { pkgs = pkgs // packages."${system}"; }; 61 | 62 | defaultPackage = packages."${system}".org2jekyll; 63 | }); 64 | } 65 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "locked": { 5 | "lastModified": 1629481132, 6 | "narHash": "sha256-JHgasjPR0/J1J3DRm4KxM4zTyAj4IOJY8vIl75v/kPI=", 7 | "owner": "numtide", 8 | "repo": "flake-utils", 9 | "rev": "997f7efcb746a9c140ce1f13c72263189225f482", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "numtide", 14 | "ref": "master", 15 | "repo": "flake-utils", 16 | "type": "github" 17 | } 18 | }, 19 | "lowdown-src": { 20 | "flake": false, 21 | "locked": { 22 | "lastModified": 1617481909, 23 | "narHash": "sha256-SqnfOFuLuVRRNeVJr1yeEPJue/qWoCp5N6o5Kr///p4=", 24 | "owner": "kristapsdz", 25 | "repo": "lowdown", 26 | "rev": "148f9b2f586c41b7e36e73009db43ea68c7a1a4d", 27 | "type": "github" 28 | }, 29 | "original": { 30 | "owner": "kristapsdz", 31 | "ref": "VERSION_0_8_4", 32 | "repo": "lowdown", 33 | "type": "github" 34 | } 35 | }, 36 | "nix": { 37 | "inputs": { 38 | "lowdown-src": "lowdown-src", 39 | "nixpkgs": "nixpkgs" 40 | }, 41 | "locked": { 42 | "lastModified": 1629716742, 43 | "narHash": "sha256-H+ISQ6m7YJFNbS1RnW14WAuKNRReEqL6y95UIJPAxAM=", 44 | "owner": "NixOS", 45 | "repo": "nix", 46 | "rev": "af94b54db3a2be100731a215cb5e95f306471731", 47 | "type": "github" 48 | }, 49 | "original": { 50 | "id": "nix", 51 | "type": "indirect" 52 | } 53 | }, 54 | "nixpkgs": { 55 | "locked": { 56 | "lastModified": 1628689438, 57 | "narHash": "sha256-YMINW6YmubHZVdliGsAJpnnMYXRrvppv59LgwtnyYhs=", 58 | "owner": "NixOS", 59 | "repo": "nixpkgs", 60 | "rev": "f6551e1efa261568c82b76c3a582b2c2ceb1f53f", 61 | "type": "github" 62 | }, 63 | "original": { 64 | "id": "nixpkgs", 65 | "ref": "nixos-21.05-small", 66 | "type": "indirect" 67 | } 68 | }, 69 | "root": { 70 | "inputs": { 71 | "flake-utils": "flake-utils", 72 | "nix": "nix", 73 | "nixpkgs": [ 74 | "nix", 75 | "nixpkgs" 76 | ] 77 | } 78 | } 79 | }, 80 | "root": "root", 81 | "version": 7 82 | } 83 | -------------------------------------------------------------------------------- /testing-blog/_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | # 11 | # If you need help with YAML syntax, here are some quick references for you:xk 12 | # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml 13 | # https://learnxinyminutes.com/docs/yaml/ 14 | # 15 | # Site settings 16 | # These are used to personalize your new site. If you look in the HTML files, 17 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 18 | # You can create any custom variable you would like, and they will be accessible 19 | # in the templates via {{ site.myvariable }}. 20 | 21 | title: Legendary blog for testing purposes 22 | email: tony@purpose.test 23 | description: >- # this means to ignore newlines until "baseurl:" 24 | Awesome description of blog post to ensure org2jekyll works the way it's 25 | supposed t line in _config.yml. It will appear in your document head meta 26 | (for Google search results) and in your feed.xml site description. 27 | 28 | baseurl: "" # the subpath of your site, e.g. /blog 29 | url: "" # the base hostname & protocol for your site, e.g. http://example.com 30 | twitter_username: "drjekyll&mrtony" 31 | github_username: "drjekyll&mrtony" 32 | 33 | # Build settings 34 | theme: minima 35 | plugins: 36 | - jekyll-feed 37 | 38 | defaults: 39 | - scope: 40 | path: "assets/img" 41 | values: 42 | image: true 43 | 44 | # Exclude from processing. 45 | # The following items will not be processed, by default. 46 | # Any item listed under the `exclude:` key here will be automatically added to 47 | # the internal "default list". 48 | # 49 | # Excluded items can be processed by explicitly listing the directories or 50 | # their entries' file path in the `include:` list. 51 | # 52 | # exclude: 53 | # - .sass-cache/ 54 | # - .jekyll-cache/ 55 | # - gemfiles/ 56 | # - Gemfile 57 | # - Gemfile.lock 58 | # - node_modules/ 59 | # - vendor/bundle/ 60 | # - vendor/cache/ 61 | # - vendor/gems/ 62 | # - vendor/ruby/ 63 | -------------------------------------------------------------------------------- /testing-blog/testing-blog-config.el: -------------------------------------------------------------------------------- 1 | ;;; testing-blog-config.el --- -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (C) 2020 Antoine R. Dumont (@ardumont) 4 | 5 | ;; Author: Antoine R. Dumont (@ardumont) 6 | ;; Keywords: 7 | 8 | ;; This program is free software; you can redistribute it and/or modify 9 | ;; it under the terms of the GNU General Public License as published by 10 | ;; the Free Software Foundation, either version 3 of the License, or 11 | ;; (at your option) any later version. 12 | 13 | ;; This program is distributed in the hope that it will be useful, 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ;; GNU General Public License for more details. 17 | 18 | ;; You should have received a copy of the GNU General Public License 19 | ;; along with this program. If not, see . 20 | 21 | ;;; Commentary: 22 | 23 | ;; 24 | 25 | ;;; Code: 26 | 27 | (require 'org) 28 | 29 | (setq org-publish-cache nil) 30 | 31 | (custom-set-variables 32 | ;; org specifics to make the tryouts reproducible here 33 | '(org-publish-use-timestamps-flag nil) ;; testing: no timestamp checking and always publish all files 34 | '(org-publish-timestamp-directory (expand-file-name "./org-timestamps/")) 35 | 36 | ;; org2jekyll specifics 37 | '(org2jekyll-jekyll-layout-page "page") 38 | '(org2jekyll-jekyll-layouts '("page" "post")) 39 | '(org2jekyll-blog-author "drjekyll&mrtony") 40 | '(org2jekyll-source-directory (expand-file-name "org")) 41 | '(org2jekyll-jekyll-directory (expand-file-name "")) 42 | '(org2jekyll-jekyll-drafts-dir "_drafts") 43 | '(org2jekyll-jekyll-posts-dir "_posts/") 44 | '(org-publish-project-alist 45 | `(("page" ;; for mostly static pages (not blog post): about-me, contacts, etc... 46 | :base-directory ,(org2jekyll-input-directory) 47 | :base-extension "org" 48 | :publishing-directory ,(org2jekyll-output-directory) 49 | :publishing-function org-html-publish-to-html 50 | :html-head "" 51 | :html-preamble t 52 | :recursive t 53 | :make-index t 54 | :html-extension "html" 55 | :body-only t) 56 | ("post" ;; dynamic blog posts 57 | :base-directory ,(org2jekyll-input-directory) 58 | :base-extension "org" 59 | :publishing-directory ,(org2jekyll-output-directory org2jekyll-jekyll-posts-dir) 60 | :publishing-function org-html-publish-to-html 61 | :html-head "" 62 | :html-preamble t 63 | :recursive t 64 | :make-index t 65 | :html-extension "html" 66 | :body-only t) 67 | ("images" 68 | :base-directory ,(org2jekyll-input-directory "img") 69 | :base-extension "jpg\\|gif\\|png" 70 | :publishing-directory ,(org2jekyll-output-directory "assets/img") 71 | :publishing-function org-publish-attachment 72 | :recursive t) 73 | ("js" 74 | :base-directory ,(org2jekyll-input-directory "js") 75 | :base-extension "js" 76 | :publishing-directory ,(org2jekyll-output-directory "assets/js") 77 | :publishing-function org-publish-attachment 78 | :recursive t) 79 | ("css" 80 | :base-directory ,(org2jekyll-input-directory "css") 81 | :base-extension "css\\|el" 82 | :publishing-directory ,(org2jekyll-output-directory "assets/css") 83 | :publishing-function org-publish-attachment 84 | :recursive t) 85 | ("web" :components ("images" "js" "css"))))) 86 | 87 | (provide 'testing-blog-config) 88 | ;;; testing-blog-config.el ends here 89 | -------------------------------------------------------------------------------- /testing-blog/org/blogging-with-org2jekyll.org: -------------------------------------------------------------------------------- 1 | #+STARTUP: showall 2 | #+STARTUP: hidestars 3 | #+OPTIONS: H:2 num:t tags:t toc:t timestamps:t 4 | #+LAYOUT: post 5 | #+AUTHOR: drjekyll&mrtony 6 | #+DATE: 2020-05-09 Sat 12:34 7 | #+TITLE: Blogging with org2jekyll setup 8 | #+DESCRIPTION: A post demo to blog with org2jekyll 9 | #+TAGS: blog org2jekyll setup jekyll 10 | #+CATEGORIES: blog org2jekyll setup jekyll 11 | #+PERMALINK: /blogging-with-org2jekyll-setup 12 | 13 | In this post, we will show how to setup org2jekyll and play with a local jekyll 14 | instance. 15 | 16 | For this, we will be using a mix of nix tools (e.g. [[https://nixos.wiki/wiki/Development_environment_with_nix-shell][nix-shell]]) and standard 17 | Makefile. The end-goal being reproducibility. 18 | 19 | Do not only trust what you read, try and reproduce it yourself following this. 20 | 21 | * Enter environment 22 | 23 | To make your environment with jekyll aware system: 24 | #+BEGIN_SRC shell 25 | $ nix-shell 26 | #+END_SRC 27 | 28 | This will install the necessary tools for a jekyll to run locally. You need nix 29 | to be installed though *¯\_(ツ)_/¯*. The dependency cycle must start somewhere 30 | heh. 31 | 32 | Then, to run the instance: 33 | 34 | #+BEGIN_SRC shell 35 | $ make update run-dev 36 | #+END_SRC 37 | 38 | Note: `update` is needed the first time around to install the necessary 39 | dependencies. 40 | 41 | Open your browser and head over [[http://localhost:4000][your running instance]]. 42 | 43 | Everything should be fine and you should see a basic jekyll instance running 44 | 45 | * Setup your emacs 46 | 47 | ** Install org2jekyll 48 | 49 | If you do not have installed org2jekyll yet, it's fine, you can always 50 | temporarily activate it through emacs' buffer loading mechanism. 51 | 52 | Open [[https://github.com/ardumont/org2jekyll/blob/master/org2jekyll.el][org2jekyll.el]] with emacs, load it (**M-x eval-buffer**). 53 | 54 | ** Setup org2jekyll 55 | 56 | Open [[https://github.com/ardumont/org2jekyll/blob/master/testing-blog/testing-blog-config.el][testing-blog-config.el]] with emacs, load it (**M-x eval-buffer**). 57 | 58 | Note that this file should really be somewhere in your personal emacs 59 | configuration stanza. It's declared here so it's publicly available ;) 60 | 61 | You should now be able to play with org2jekyll. And then check the result in 62 | the jekyll instance. 63 | 64 | * Create a blog post 65 | 66 | **M-x org2jekyll-create-draft** and follow the minibuffer questions. Choose the 67 | layout "post" (in the current configuration). 68 | 69 | Write some awesome stuff as you see fit, the org way. 70 | 71 | When done, publish: **M-x org2jekyll-publish**. 72 | 73 | From your browser, refresh your [[http://localhost:4000][your running instance]]. 74 | You should now see your blog post published there. 75 | 76 | You can loop over edition in org and publish until you are satisfied. 77 | 78 | * Create a static page 79 | 80 | You can also edit static pages. 81 | 82 | For example a page about you, call it *about-me.org* 83 | 84 | **M-x org2jekyll-create-draft**, follow the minibuffer questions. Choose the 85 | layout "default" (in the current configuration). 86 | 87 | The write some things about yourself the org way. 88 | 89 | Optionally, you can add **#+PERMALINK: ** header. 90 | 91 | When done, **M-x org2jekyll-publish**. 92 | 93 | From your browser, refresh your [[http://localhost:4000][your running instance]]. 94 | 95 | You should now see your about-me page there, not alongside the listed blog 96 | posts though. In the title menu bar. 97 | 98 | If you don't find, depending on some jekyll configuration, you can always head 99 | over the [[http://localhost:4000/about-me][about-me page]] (if you used the extra permalink mentioned). 100 | 101 | * Evaluate block code the org-mode way 102 | 103 | Make your emacs able to deal with [[https://gitlab.com/ardumont/home/-/blob/5afd58b89517dbe03a1510ce4fadb5200d80c5bb/emacs/default.nix#L140-142][python and matplotlib for the following]]. 104 | 105 | Evaluate the block (**C-c C-c**) to have the results below. 106 | 107 | #+BEGIN_SRC python :session :results t :exports t 108 | import os 109 | import matplotlib 110 | import matplotlib.pyplot as plt 111 | import numpy as np 112 | 113 | t = np.arange(0.0, 2.0, 0.01) 114 | s = 1 + np.sin(2 * np.pi * t) 115 | 116 | fig, ax = plt.subplots() 117 | ax.plot(t, s) 118 | 119 | ax.set(xlabel='time (s)', ylabel='voltage (mV)', title='Voltage over time') 120 | ax.grid() 121 | 122 | os.makedirs("./img", exist_ok=True) 123 | fig.savefig("./img/plot-sin.png") 124 | #+END_SRC 125 | 126 | #+RESULTS: 127 | | Text | (33.722222222222214 0.5 voltage (mV)) | Text | (0.5 23.52222222222222 time (s)) | Text | (0.5 1 Voltage over time) | 128 | 129 | * Display image 130 | 131 | Check your [[https://github.com/ardumont/org2jekyll/blob/master/testing-blog/_config.yml][_config.yml]] to determine where to store images. 132 | 133 | http://localhost:4000/assets/img/plot-sin.png 134 | 135 | source: https://matplotlib.org/gallery/lines_bars_and_markers/simple_plot.html 136 | -------------------------------------------------------------------------------- /todo.org: -------------------------------------------------------------------------------- 1 | #+title: Backlog 2 | #+author: ardumont 3 | 4 | * DONE 0.2.7 [100%] 5 | CLOSED: [2020-06-01 Mon 19:42] 6 | - [X] Fix ci 7 | - [X] Close #66: Properly link to internal publications 8 | - [X] Clean dead code 9 | * DONE 0.2.6 [100%] 10 | CLOSED: [2020-05-27 Wed 21:14] 11 | - [X] Update missing documentations 12 | - [X] Make the testing-blog even more reproducible (through nix-shell) 13 | - [X] Close #63 - Fix org2jekyll-publish-posts & org2jekyll-publish-pages 14 | * DONE 0.2.5 [100%] 15 | CLOSED: [2020-05-21 Thu 18:55] 16 | - [X] Drop lexical-let dependency 17 | - [X] Drop deferred dependency 18 | - [X] Add missing coverage which was somehow wrong (apparent after lexical-let 19 | dismissal) 20 | * DONE 0.2.4 [100%] 21 | CLOSED: [2020-05-21 Thu 01:26] 22 | - [X] Drop-kv-dependency origin/drop-kv-dependency Remove kv dependency as we can 23 | avoid it 24 | - [X] Define variables locally to where it's needed 25 | * DONE 0.2.3 [100%] 26 | CLOSED: [2020-05-17 Sun 16:05] 27 | - [X] Allow draft template headers customization 28 | - [X] Fix page publication which was no longer edited with yaml since the hook 29 | change 30 | * DONE 0.2.2 [100%] 31 | CLOSED: [2020-05-16 Sat 16:53] 32 | - [X] Allow toc generation (respect more the org-mode user setup) 33 | - [X] Update README about those changes 34 | - [X] Fix misindentation in function org2jekyll-publish 35 | * DONE 0.2.1 [100%] 36 | CLOSED: [2020-05-16 Sat 08:28] 37 | - [X] Update version and doc about new changes 38 | - [X] Respect the user setup regarding tags option export (align with org-mode) 39 | - [X] Define org2jekyll tags/categories as space separated values (align with 40 | org-mode) 41 | - [X] Fix issue on time formatting which prevented rendering jekyll side 42 | 43 | * DONE 0.2.0 [100%] 44 | CLOSED: [2020-05-09 Sat 18:10] 45 | - [X] #46: Improve yaml date format 46 | - [X] #53: Allow defining specific layouts in yaml header 47 | - [X] Present a demonstration runnable from the repository 48 | - [X] Update documentations 49 | - [X] Update ci tools 50 | * DONE 0.1.9 [100%] 51 | CLOSED: [2016-04-16 Sat 18:36] 52 | - [X] Permit to add extra yaml headers during export with user-custom variable (#34) 53 | - [X] Support the new org-mode export block syntax with retro-compatibility (#32) 54 | - [X] Refactoring on internal function names 55 | - [X] Add MELPA and license badges 56 | - [X] Doc - Improvments (#33) 57 | - [X] CI - Improvments (#31) 58 | - [X] Packaging - Sign annotated tag during release 59 | - [X] Packaging - Switch to new version of evm. 60 | - [X] Packaging - Rename utilities.el to org2jekyll-utilities.el (#30) 61 | - [X] Upgrade version 62 | 63 | * DONE 0.1.8 [100%] 64 | CLOSED: [2015-09-06 Sun 15:44] 65 | - [X] Update version 66 | - [X] Improve deployment script 67 | - [X] Code convention (limit to 80 characters line) 68 | - [X] Close #27 - Add headers to current buffer 69 | - [X] Close #26 - fix potential page publishing problem 70 | - [X] Improve coverage 71 | * DONE 0.1.7 [100%] 72 | CLOSED: [2015-07-14 Tue 16:35] 73 | - [X] Update version 74 | - [X] Update org2jekyll dependencies 75 | - [X] #22 - Add tags feature 76 | - [X] Improve completion for post/default type 77 | * DONE 0.1.6 [100%] 78 | CLOSED: [2015-06-30 Tue 13:35] 79 | - [X] Update version 80 | - [X] Fix org2jekyll-create-draft limits for international characters #20 81 | - [X] Release notes 82 | * DONE 0.1.5 [100%] 83 | CLOSED: [2015-05-15 Fri 17:11] 84 | - [X] Update version 85 | - [X] org2jekyll must publish images, js, css - #18 86 | - [X] Fix release.sh regarding version not initialized 87 | - [X] Automate marmalade deploy 88 | * DONE 0.1.4 [100%] 89 | CLOSED: [2015-02-16 Mon 22:22] 90 | - [X] Internal - Fix docstring (thanks @purcell) 91 | - [X] Rename functions to respect conventions (again, I missed the `!` in names) 92 | - [X] Reference recipes in el-get and melpa 93 | - [X] Create melpa recipe and propose PR - https://github.com/milkypostman/melpa/pull/2513 94 | - [X] Create el-get recipe and propose PR - https://github.com/dimitri/el-get/pull/2095 95 | - [X] Update version 96 | - [X] Remove unused org2jekyll-pkg.el file and adapt Makefile - https://github.com/milkypostman/melpa/pull/2513#issuecomment-74561073 97 | * DONE 0.1.3 [100%] 98 | CLOSED: [2015-02-16 Mon 19:12] 99 | - [X] Update version 100 | - [X] Respect elisp coding convention 101 | - [X] Mention the breaking api names in calling function names in the readme. 102 | - [X] Alias old function names for compatibility's sake 103 | - [X] Update formatting code 104 | * DONE 0.1.2 [100%] 105 | CLOSED: [2015-01-24 Sat 21:24] 106 | - [X] Fix error on draft header creation - https://github.com/ardumont/org2jekyll/pull/12 107 | - [X] Update version 108 | * DONE 0.1.1 [100%] 109 | CLOSED: [2014-12-27 Sat 00:32] 110 | - [X] Create backlog 111 | - [X] Update version 112 | - [X] Permit the publication of all the posts + binding 113 | - [X] Permit the publication of all the pages 114 | - [X] Update docs 115 | * DONE 0.1.0 [100%] 116 | CLOSED: [2014-12-26 Fri 16:25] 117 | - [X] Create backlog 118 | - [X] Update version 119 | - [X] Fix default binding in org2jekyll-mode 120 | - [X] Make the publish! action asynchronous [2/2] 121 | - [X] Close not-needed interactive command and make them function 122 | - [X] Render asynchronous the main org2jekyll/publish! command 123 | - [X] Add checks on header and explain what's missing if problems. 124 | * DONE 0.0.9 [100%] 125 | CLOSED: [2014-12-26 Fri 09:26] 126 | - [X] Create backlog 127 | - [X] Update version 128 | - [X] Ask for desired layout when creating a draft 129 | * DONE 0.0.8 [100%] 130 | CLOSED: [2014-12-24 Wed 18:24] 131 | - [X] Create backlog 132 | - [X] Update version 133 | - [X] Fix implementation of output-directory function 134 | - [X] Remove unused dependency deferred (for the moment not used) 135 | - [X] Improve doc (header + README.org + customization group + install step) 136 | - [X] Create minor mode with default bindings 137 | - [X] Update readme about minor mode 138 | - [X] Add TOC to readme 139 | 140 | * DONE 0.0.7 [100%] 141 | CLOSED: [2014-12-20 Sat 18:22] 142 | - [X] Create backlog 143 | - [X] Update version 144 | - [X] Permit to publish jekyll ready html page (not blog post) using the same mechanism as blog post 145 | - [X] Expose only one command to publish post or html page 146 | - [X] Merge the jekyll `layout` notion with the org `project` notion 147 | - [X] Update documentation about the new possibilities 148 | * DONE 0.0.6 [100%] 149 | `CLOSED: [2014-12-20 Sat 13:05] 150 | - [X] Create backlog 151 | - [X] Update version 152 | - [X] Remove dead code 153 | - [X] Fix draft folder computation to be in source input directory 154 | - [X] Permit the blog metadata to determine the desired layout 155 | - [X] Refactor main function in multiple sub functions to ease testing 156 | - [X] Update deps version 157 | - [X] Permit options to be null without breaking jekyll publishing 158 | - [X] Ensure install works with clean install mechanism 159 | - [X] When publishing remove the org2jekyll/jekyll-drafts-dir arborescence 160 | - [X] Improve default header computation 161 | - [X] Fix ci-travis for emacs 24.3 162 | - [X] Add ci-travis status badge 163 | * DONE 0.0.5 [100%] 164 | CLOSED: [2014-12-20 Sat 00:45] 165 | - [X] Create backlog 166 | - [X] Update version 167 | - [X] No toc in the default template header 168 | * DONE 0.0.4 [100%] 169 | CLOSED: [2014-12-20 Sat 00:01] 170 | - [X] Create backlog 171 | - [X] Update version 172 | - [X] Fix draft template creation 173 | - [X] Generate date when draft creation 174 | - [X] Ask for categories and description for draft creation 175 | - [X] Update README.org 176 | - [X] Create a simple readme section in org2jekyll.el 177 | * DONE 0.0.3 [100%] 178 | CLOSED: [2014-12-19 Sat 23:36] 179 | - [X] Create backlog 180 | - [X] Update version 181 | - [X] Add autoloads on public functions 182 | - [X] Improve README.org documentation 183 | - [X] Use custom variables + update doc 184 | * DONE 0.0.2 [100%] 185 | CLOSED: [2014-12-19 Fri 22:16] 186 | - [X] Create backlog 187 | - [X] Add release script 188 | - [X] Update version 189 | - [X] Release to marmalade - https://marmalade-repo.org/packages/org2jekyll 190 | * DONE 0.0.1 [100%] 191 | CLOSED: [2014-12-19 Fri 22:03] 192 | - [X] Create backlog 193 | - [X] Retrieve existing code from https://github.com/ardumont/ardumont.github.io 194 | - [X] Add Cask 195 | - [X] Create package 196 | - [X] Ensure tests are ok + Make tests launchable 197 | - [X] Add ci-travis 198 | -------------------------------------------------------------------------------- /testing-blog/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (6.0.4.1) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 0.7, < 2) 7 | minitest (~> 5.1) 8 | tzinfo (~> 1.1) 9 | zeitwerk (~> 2.2, >= 2.2.2) 10 | addressable (2.8.0) 11 | public_suffix (>= 2.0.2, < 5.0) 12 | coffee-script (2.4.1) 13 | coffee-script-source 14 | execjs 15 | coffee-script-source (1.11.1) 16 | colorator (1.1.0) 17 | commonmarker (0.17.13) 18 | ruby-enum (~> 0.5) 19 | concurrent-ruby (1.1.9) 20 | dnsruby (1.61.7) 21 | simpleidn (~> 0.1) 22 | em-websocket (0.5.2) 23 | eventmachine (>= 0.12.9) 24 | http_parser.rb (~> 0.6.0) 25 | ethon (0.14.0) 26 | ffi (>= 1.15.0) 27 | eventmachine (1.2.7) 28 | execjs (2.8.1) 29 | faraday (1.7.1) 30 | faraday-em_http (~> 1.0) 31 | faraday-em_synchrony (~> 1.0) 32 | faraday-excon (~> 1.1) 33 | faraday-httpclient (~> 1.0.1) 34 | faraday-net_http (~> 1.0) 35 | faraday-net_http_persistent (~> 1.1) 36 | faraday-patron (~> 1.0) 37 | faraday-rack (~> 1.0) 38 | multipart-post (>= 1.2, < 3) 39 | ruby2_keywords (>= 0.0.4) 40 | faraday-em_http (1.0.0) 41 | faraday-em_synchrony (1.0.0) 42 | faraday-excon (1.1.0) 43 | faraday-httpclient (1.0.1) 44 | faraday-net_http (1.0.1) 45 | faraday-net_http_persistent (1.2.0) 46 | faraday-patron (1.0.0) 47 | faraday-rack (1.0.0) 48 | ffi (1.15.3) 49 | forwardable-extended (2.6.0) 50 | gemoji (3.0.1) 51 | github-pages (219) 52 | github-pages-health-check (= 1.17.7) 53 | jekyll (= 3.9.0) 54 | jekyll-avatar (= 0.7.0) 55 | jekyll-coffeescript (= 1.1.1) 56 | jekyll-commonmark-ghpages (= 0.1.6) 57 | jekyll-default-layout (= 0.1.4) 58 | jekyll-feed (= 0.15.1) 59 | jekyll-gist (= 1.5.0) 60 | jekyll-github-metadata (= 2.13.0) 61 | jekyll-mentions (= 1.6.0) 62 | jekyll-optional-front-matter (= 0.3.2) 63 | jekyll-paginate (= 1.1.0) 64 | jekyll-readme-index (= 0.3.0) 65 | jekyll-redirect-from (= 0.16.0) 66 | jekyll-relative-links (= 0.6.1) 67 | jekyll-remote-theme (= 0.4.3) 68 | jekyll-sass-converter (= 1.5.2) 69 | jekyll-seo-tag (= 2.7.1) 70 | jekyll-sitemap (= 1.4.0) 71 | jekyll-swiss (= 1.0.0) 72 | jekyll-theme-architect (= 0.2.0) 73 | jekyll-theme-cayman (= 0.2.0) 74 | jekyll-theme-dinky (= 0.2.0) 75 | jekyll-theme-hacker (= 0.2.0) 76 | jekyll-theme-leap-day (= 0.2.0) 77 | jekyll-theme-merlot (= 0.2.0) 78 | jekyll-theme-midnight (= 0.2.0) 79 | jekyll-theme-minimal (= 0.2.0) 80 | jekyll-theme-modernist (= 0.2.0) 81 | jekyll-theme-primer (= 0.6.0) 82 | jekyll-theme-slate (= 0.2.0) 83 | jekyll-theme-tactile (= 0.2.0) 84 | jekyll-theme-time-machine (= 0.2.0) 85 | jekyll-titles-from-headings (= 0.5.3) 86 | jemoji (= 0.12.0) 87 | kramdown (= 2.3.1) 88 | kramdown-parser-gfm (= 1.1.0) 89 | liquid (= 4.0.3) 90 | mercenary (~> 0.3) 91 | minima (= 2.5.1) 92 | nokogiri (>= 1.10.4, < 2.0) 93 | rouge (= 3.26.0) 94 | terminal-table (~> 1.4) 95 | github-pages-health-check (1.17.7) 96 | addressable (~> 2.3) 97 | dnsruby (~> 1.60) 98 | octokit (~> 4.0) 99 | public_suffix (>= 3.0, < 5.0) 100 | typhoeus (~> 1.3) 101 | html-pipeline (2.14.0) 102 | activesupport (>= 2) 103 | nokogiri (>= 1.4) 104 | http_parser.rb (0.6.0) 105 | i18n (0.9.5) 106 | concurrent-ruby (~> 1.0) 107 | jekyll (3.9.0) 108 | addressable (~> 2.4) 109 | colorator (~> 1.0) 110 | em-websocket (~> 0.5) 111 | i18n (~> 0.7) 112 | jekyll-sass-converter (~> 1.0) 113 | jekyll-watch (~> 2.0) 114 | kramdown (>= 1.17, < 3) 115 | liquid (~> 4.0) 116 | mercenary (~> 0.3.3) 117 | pathutil (~> 0.9) 118 | rouge (>= 1.7, < 4) 119 | safe_yaml (~> 1.0) 120 | jekyll-avatar (0.7.0) 121 | jekyll (>= 3.0, < 5.0) 122 | jekyll-coffeescript (1.1.1) 123 | coffee-script (~> 2.2) 124 | coffee-script-source (~> 1.11.1) 125 | jekyll-commonmark (1.3.1) 126 | commonmarker (~> 0.14) 127 | jekyll (>= 3.7, < 5.0) 128 | jekyll-commonmark-ghpages (0.1.6) 129 | commonmarker (~> 0.17.6) 130 | jekyll-commonmark (~> 1.2) 131 | rouge (>= 2.0, < 4.0) 132 | jekyll-default-layout (0.1.4) 133 | jekyll (~> 3.0) 134 | jekyll-feed (0.15.1) 135 | jekyll (>= 3.7, < 5.0) 136 | jekyll-gist (1.5.0) 137 | octokit (~> 4.2) 138 | jekyll-github-metadata (2.13.0) 139 | jekyll (>= 3.4, < 5.0) 140 | octokit (~> 4.0, != 4.4.0) 141 | jekyll-mentions (1.6.0) 142 | html-pipeline (~> 2.3) 143 | jekyll (>= 3.7, < 5.0) 144 | jekyll-optional-front-matter (0.3.2) 145 | jekyll (>= 3.0, < 5.0) 146 | jekyll-paginate (1.1.0) 147 | jekyll-readme-index (0.3.0) 148 | jekyll (>= 3.0, < 5.0) 149 | jekyll-redirect-from (0.16.0) 150 | jekyll (>= 3.3, < 5.0) 151 | jekyll-relative-links (0.6.1) 152 | jekyll (>= 3.3, < 5.0) 153 | jekyll-remote-theme (0.4.3) 154 | addressable (~> 2.0) 155 | jekyll (>= 3.5, < 5.0) 156 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) 157 | rubyzip (>= 1.3.0, < 3.0) 158 | jekyll-sass-converter (1.5.2) 159 | sass (~> 3.4) 160 | jekyll-seo-tag (2.7.1) 161 | jekyll (>= 3.8, < 5.0) 162 | jekyll-sitemap (1.4.0) 163 | jekyll (>= 3.7, < 5.0) 164 | jekyll-swiss (1.0.0) 165 | jekyll-theme-architect (0.2.0) 166 | jekyll (> 3.5, < 5.0) 167 | jekyll-seo-tag (~> 2.0) 168 | jekyll-theme-cayman (0.2.0) 169 | jekyll (> 3.5, < 5.0) 170 | jekyll-seo-tag (~> 2.0) 171 | jekyll-theme-dinky (0.2.0) 172 | jekyll (> 3.5, < 5.0) 173 | jekyll-seo-tag (~> 2.0) 174 | jekyll-theme-hacker (0.2.0) 175 | jekyll (> 3.5, < 5.0) 176 | jekyll-seo-tag (~> 2.0) 177 | jekyll-theme-leap-day (0.2.0) 178 | jekyll (> 3.5, < 5.0) 179 | jekyll-seo-tag (~> 2.0) 180 | jekyll-theme-merlot (0.2.0) 181 | jekyll (> 3.5, < 5.0) 182 | jekyll-seo-tag (~> 2.0) 183 | jekyll-theme-midnight (0.2.0) 184 | jekyll (> 3.5, < 5.0) 185 | jekyll-seo-tag (~> 2.0) 186 | jekyll-theme-minimal (0.2.0) 187 | jekyll (> 3.5, < 5.0) 188 | jekyll-seo-tag (~> 2.0) 189 | jekyll-theme-modernist (0.2.0) 190 | jekyll (> 3.5, < 5.0) 191 | jekyll-seo-tag (~> 2.0) 192 | jekyll-theme-primer (0.6.0) 193 | jekyll (> 3.5, < 5.0) 194 | jekyll-github-metadata (~> 2.9) 195 | jekyll-seo-tag (~> 2.0) 196 | jekyll-theme-slate (0.2.0) 197 | jekyll (> 3.5, < 5.0) 198 | jekyll-seo-tag (~> 2.0) 199 | jekyll-theme-tactile (0.2.0) 200 | jekyll (> 3.5, < 5.0) 201 | jekyll-seo-tag (~> 2.0) 202 | jekyll-theme-time-machine (0.2.0) 203 | jekyll (> 3.5, < 5.0) 204 | jekyll-seo-tag (~> 2.0) 205 | jekyll-titles-from-headings (0.5.3) 206 | jekyll (>= 3.3, < 5.0) 207 | jekyll-watch (2.2.1) 208 | listen (~> 3.0) 209 | jemoji (0.12.0) 210 | gemoji (~> 3.0) 211 | html-pipeline (~> 2.2) 212 | jekyll (>= 3.0, < 5.0) 213 | kramdown (2.3.1) 214 | rexml 215 | kramdown-parser-gfm (1.1.0) 216 | kramdown (~> 2.0) 217 | liquid (4.0.3) 218 | listen (3.7.0) 219 | rb-fsevent (~> 0.10, >= 0.10.3) 220 | rb-inotify (~> 0.9, >= 0.9.10) 221 | mercenary (0.3.6) 222 | mini_portile2 (2.6.1) 223 | minima (2.5.1) 224 | jekyll (>= 3.5, < 5.0) 225 | jekyll-feed (~> 0.9) 226 | jekyll-seo-tag (~> 2.1) 227 | minitest (5.14.4) 228 | multipart-post (2.1.1) 229 | nokogiri (1.12.5) 230 | mini_portile2 (~> 2.6.1) 231 | racc (~> 1.4) 232 | octokit (4.21.0) 233 | faraday (>= 0.9) 234 | sawyer (~> 0.8.0, >= 0.5.3) 235 | pathutil (0.16.2) 236 | forwardable-extended (~> 2.6) 237 | public_suffix (4.0.6) 238 | racc (1.5.2) 239 | rb-fsevent (0.11.0) 240 | rb-inotify (0.10.1) 241 | ffi (~> 1.0) 242 | rexml (3.2.5) 243 | rouge (3.26.0) 244 | ruby-enum (0.9.0) 245 | i18n 246 | ruby2_keywords (0.0.5) 247 | rubyzip (2.3.2) 248 | safe_yaml (1.0.5) 249 | sass (3.7.4) 250 | sass-listen (~> 4.0.0) 251 | sass-listen (4.0.0) 252 | rb-fsevent (~> 0.9, >= 0.9.4) 253 | rb-inotify (~> 0.9, >= 0.9.7) 254 | sawyer (0.8.2) 255 | addressable (>= 2.3.5) 256 | faraday (> 0.8, < 2.0) 257 | simpleidn (0.2.1) 258 | unf (~> 0.1.4) 259 | terminal-table (1.8.0) 260 | unicode-display_width (~> 1.1, >= 1.1.1) 261 | thread_safe (0.3.6) 262 | typhoeus (1.4.0) 263 | ethon (>= 0.9.0) 264 | tzinfo (1.2.9) 265 | thread_safe (~> 0.1) 266 | unf (0.1.4) 267 | unf_ext 268 | unf_ext (0.0.7.7) 269 | unicode-display_width (1.7.0) 270 | zeitwerk (2.4.2) 271 | 272 | PLATFORMS 273 | ruby 274 | 275 | DEPENDENCIES 276 | github-pages 277 | 278 | BUNDLED WITH 279 | 2.1.4 280 | -------------------------------------------------------------------------------- /testing-blog/_posts/2020-05-09-blogging-with-org2jekyll.html: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-05-09 12:34 3 | author: drjekyll&mrtony 4 | layout: post 5 | title: Blogging with org2jekyll setup 6 | excerpt: A post demo to blog with org2jekyll 7 | tags: 8 | - blog 9 | - org2jekyll 10 | - setup 11 | - jekyll 12 | categories: 13 | - blog 14 | - org2jekyll 15 | - setup 16 | - jekyll 17 | permalink: /blogging-with-org2jekyll-setup 18 | --- 19 | 37 |

38 | In this post, we will show how to setup org2jekyll and play with a local jekyll 39 | instance. 40 |

41 | 42 |

43 | For this, we will be using a mix of nix tools (e.g. nix-shell) and standard 44 | Makefile. The end-goal being reproducibility. 45 |

46 | 47 |

48 | Do not only trust what you read, try and reproduce it yourself following this. 49 |

50 | 51 |
52 |

1 Enter environment

53 |
54 |

55 | To make your environment with jekyll aware system: 56 |

57 |
58 |
$ nix-shell
 59 | 
60 |
61 | 62 |

63 | This will install the necessary tools for a jekyll to run locally. You need nix 64 | to be installed though ¯\(ツ)_/¯. The dependency cycle must start somewhere 65 | heh. 66 |

67 | 68 |

69 | Then, to run the instance: 70 |

71 | 72 |
73 |
$ make update run-dev
 74 | 
75 |
76 | 77 |

78 | Note: `update` is needed the first time around to install the necessary 79 | dependencies. 80 |

81 | 82 |

83 | Open your browser and head over your running instance. 84 |

85 | 86 |

87 | Everything should be fine and you should see a basic jekyll instance running 88 |

89 |
90 |
91 | 92 |
93 |

2 Setup your emacs

94 |
95 |
96 |
97 |

2.1 Install org2jekyll

98 |
99 |

100 | If you do not have installed org2jekyll yet, it's fine, you can always 101 | temporarily activate it through emacs' buffer loading mechanism. 102 |

103 | 104 |

105 | Open org2jekyll.el with emacs, load it (M-x eval-buffer). 106 |

107 |
108 |
109 | 110 |
111 |

2.2 Setup org2jekyll

112 |
113 |

114 | Open testing-blog-config.el with emacs, load it (M-x eval-buffer). 115 |

116 | 117 |

118 | Note that this file should really be somewhere in your personal emacs 119 | configuration stanza. It's declared here so it's publicly available ;) 120 |

121 | 122 |

123 | You should now be able to play with org2jekyll. And then check the result in 124 | the jekyll instance. 125 |

126 |
127 |
128 |
129 | 130 |
131 |

3 Create a blog post

132 |
133 |

134 | M-x org2jekyll-create-draft and follow the minibuffer questions. Choose the 135 | layout "post" (in the current configuration). 136 |

137 | 138 |

139 | Write some awesome stuff as you see fit, the org way. 140 |

141 | 142 |

143 | When done, publish: M-x org2jekyll-publish. 144 |

145 | 146 |

147 | From your browser, refresh your your running instance. 148 | You should now see your blog post published there. 149 |

150 | 151 |

152 | You can loop over edition in org and publish until you are satisfied. 153 |

154 |
155 |
156 | 157 |
158 |

4 Create a static page

159 |
160 |

161 | You can also edit static pages. 162 |

163 | 164 |

165 | For example a page about you, call it about-me.org 166 |

167 | 168 |

169 | M-x org2jekyll-create-draft, follow the minibuffer questions. Choose the 170 | layout "default" (in the current configuration). 171 |

172 | 173 |

174 | The write some things about yourself the org way. 175 |

176 | 177 |

178 | Optionally, you can add #+PERMALINK: <whatever-you-want> header. 179 |

180 | 181 |

182 | When done, M-x org2jekyll-publish. 183 |

184 | 185 |

186 | From your browser, refresh your your running instance. 187 |

188 | 189 |

190 | You should now see your about-me page there, not alongside the listed blog 191 | posts though. In the title menu bar. 192 |

193 | 194 |

195 | If you don't find, depending on some jekyll configuration, you can always head 196 | over the about-me page (if you used the extra permalink mentioned). 197 |

198 |
199 |
200 | 201 |
202 |

5 Evaluate block code the org-mode way

203 |
204 |

205 | Make your emacs able to deal with python and matplotlib for the following. 206 |

207 | 208 |

209 | Evaluate the block (C-c C-c) to have the results below. 210 |

211 | 212 |
213 |
import os
214 | import matplotlib
215 | import matplotlib.pyplot as plt
216 | import numpy as np
217 | 
218 | t = np.arange(0.0, 2.0, 0.01)
219 | s = 1 + np.sin(2 * np.pi * t)
220 | 
221 | fig, ax = plt.subplots()
222 | ax.plot(t, s)
223 | 
224 | ax.set(xlabel='time (s)', ylabel='voltage (mV)', title='Voltage over time')
225 | ax.grid()
226 | 
227 | os.makedirs("./img", exist_ok=True)
228 | fig.savefig("./img/plot-sin.png")
229 | 
230 |
231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 |
Text(33.722222222222214 0.5 voltage (mV))Text(0.5 23.52222222222222 time (s))Text(0.5 1 Voltage over time)
259 |
260 |
261 | 262 |
263 |

6 Display image

264 |
265 |

266 | Check your _config.yml to determine where to store images. 267 |

268 | 269 | 270 |
271 |

plot-sin.png 272 |

273 |
274 | 275 |

276 | source: https://matplotlib.org/gallery/lines_bars_and_markers/simple_plot.html 277 |

278 |
279 |
280 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+title: org2jekyll 2 | #+author: ardumont 3 | 4 | [[https://travis-ci.org/ardumont/org2jekyll][file:https://travis-ci.org/ardumont/org2jekyll.svg?branch=master]] 5 | [[https://coveralls.io/github/ardumont/org2jekyll?branch=master][file:https://coveralls.io/repos/github/ardumont/org2jekyll/badge.svg?branch=master]] 6 | [[https://melpa.org/#/org2jekyll][file:https://melpa.org/packages/org2jekyll-badge.svg]] 7 | [[https://stable.melpa.org/#/org2jekyll][file:https://stable.melpa.org/packages/org2jekyll-badge.svg]] 8 | [[https://www.gnu.org/licenses/gpl-2.0.txt][file:https://img.shields.io/:license-GPLv2-blue.svg]] 9 | [[https://archive.softwareheritage.org/badge/origin/https://github.com/ardumont/org2jekyll/][file:https://archive.softwareheritage.org/badge/origin/https://github.com/ardumont/org2jekyll/]] 10 | 11 | Blogging with org-mode and jekyll without alien yaml headers. 12 | 13 | * Table of Contents :TOC_4: 14 | - [[#upgrade][Upgrade]] 15 | - [[#026---027][0.2.6 -> 0.2.7]] 16 | - [[#022---023][0.2.2 -> 0.2.3]] 17 | - [[#021---022][0.2.1 -> 0.2.2]] 18 | - [[#020---021][0.2.0 -> 0.2.1]] 19 | - [[#018---019][0.1.8 -> 0.1.9]] 20 | - [[#012---014][0.1.2 -> 0.1.4]] 21 | - [[#description][Description]] 22 | - [[#rationale][Rationale]] 23 | - [[#pre-requisite][Pre-requisite]] 24 | - [[#installsetup][Install/Setup]] 25 | - [[#install][Install]] 26 | - [[#setup][Setup]] 27 | - [[#a-running-example][A running example]] 28 | - [[#a-reproducible-example][A reproducible example]] 29 | - [[#use][Use]] 30 | - [[#post][Post]] 31 | - [[#headers][Headers]] 32 | - [[#publish][Publish]] 33 | - [[#how][How]] 34 | - [[#extra-headers][Extra headers]] 35 | - [[#page][Page]] 36 | - [[#headers-1][Headers]] 37 | - [[#publish-1][Publish]] 38 | - [[#how-1][How]] 39 | - [[#extra-headers-1][Extra-headers]] 40 | - [[#publish-all-posts][Publish all posts]] 41 | - [[#publish-all-pages][Publish all pages]] 42 | - [[#previews][Previews]] 43 | - [[#minor-mode][Minor mode]] 44 | - [[#customization][Customization]] 45 | - [[#layout][Layout]] 46 | - [[#draft][Draft]] 47 | - [[#about-internal-publication-links][About internal publication links]] 48 | - [[#problems][Problems]] 49 | - [[#dependencies][dependencies]] 50 | 51 | * Upgrade 52 | 53 | ** 0.2.6 -> 0.2.7 54 | - We can now export properly links to other internal publications. See 55 | [[#about-internal-publication-links][#about-internal-publication-links]] for more details. 56 | 57 | ** 0.2.2 -> 0.2.3 58 | - User can now extend the default templates with default values on their own 59 | (at draft creation time). [[https://github.com/ardumont/org2jekyll/issues/47][Thanks for issue 47]] which revealed the need. See 60 | [[#Draft][#draft]] for more details. 61 | 62 | ** 0.2.1 -> 0.2.2 63 | 64 | - The toc:t is now respected. Please make sure you want your table of contents 65 | (`toc:t`) or not (`toc:nil`). 66 | - Note that org2jekyll changed internally how it's working and rely a bit 67 | further on org-mode mechanism (so it's good ;). Notably, it uses a hook at 68 | the end of the publishing step to prepend the jekyll yaml headers. You need 69 | to activate M-x org2jekyll-mode for that hook to be installed 70 | though (respectively deactivate org2jkeyll-mode to remove that hook). 71 | 72 | ** 0.2.0 -> 0.2.1 73 | 74 | - The `tags:nil` option is now respected, aligning with org-mode. So, when nil, 75 | those are not exported in yaml headers. Please make sure you want those 76 | activated (`tags:t`) or not (`tags:nil`). 77 | - When generating new org2jekyll buffer, the default option is now `tags:t` 78 | - `#+TAGS` and `#+CATEGORIES` are no longer comma separated values but space 79 | separated values. This is also to be in check with org-mode. 80 | 81 | ** 0.1.8 -> 0.1.9 82 | - Remove deprecated api function names mentioned in 0.1.2 -> 0.1.4 migration. 83 | - Allow user to define on per-buffer setup or per-custom variable basis some 84 | extra yaml header 85 | 86 | ** 0.1.2 -> 0.1.4 87 | 88 | The [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Coding-Conventions.html][elisp coding convention]] was not respected up to this version. So between 89 | the 0.1.2 and 0.1.3 version, the names and variables were updated to respect 90 | them. Now every command and variables uses `org2jekyll-` and no longer 91 | `org2jekyll/` prefix. 92 | 93 | * Description 94 | 95 | Let *org2jekyll* export your org-mode file to jekyll. 96 | 97 | What's the difference with [[https://github.com/juanre/org-jekyll][org-jekyll]]? 98 | 99 | You don't need to add some alien yaml in your org-mode file. 100 | You add specific org-mode headers and this will be used to format the jekyll post. 101 | 102 | What's the difference with [[https://github.com/bmaland/happyblogger][happyblogger]]? 103 | 104 | Only emacs' dependencies (org, etc...) no external ruby script. 105 | 106 | ** Rationale 107 | 108 | - [[http://orgmode.org/][org-mode]] rocks 109 | - Github uses [[http://jekyllrb.com/][Jekyll]] 110 | - [[http://jekyllrb.com/][Jekyll]] is nice 111 | - Existing solutions regarding org-mode and jekyll need the org-mode files to 112 | be altered with non-org notations to work together 113 | - I don't want to alter my org-mode files with alien yaml headers to satisfy 114 | jekyll 115 | 116 | Enters org2jekyll. 117 | 118 | ** Pre-requisite 119 | 120 | You have: 121 | - your [[http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html][*org-publish*]] setup ready ([[https://github.com/ardumont/blog-pack/blob/master/blog-pack.el#L13-L71][mine for example]]) 122 | - a running [[http://github.com/mojombo/jekyll][jekyll]] installation 123 | 124 | * Install/Setup 125 | 126 | ** Install 127 | 128 | Available on [[http://melpa.org/#/getting-started][melpa]]. 129 | 130 | Update your packages archives: 131 | 132 | #+begin_src emacs-lisp 133 | (require 'package) 134 | (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t) 135 | (package-initialize) 136 | #+end_src 137 | 138 | /M-x package-install RET org2jekyll RET/ 139 | 140 | ** Setup 141 | 142 | org2jekyll leverage org-mode's publish abilities (`ox-publish`), so it needs 143 | the `org-publish-project-alist` custom to be defined to something sensible 144 | regarding your blogging setup. 145 | 146 | /M-x customize-group RET org2jekyll RET/ 147 | 148 | For example, here is my [[http://ardumont.github.io/][blog site configuration]]: 149 | 150 | #+begin_src emacs-lisp 151 | (require 'org) 152 | (require 'org2jekyll) 153 | 154 | (custom-set-variables '(org2jekyll-blog-author "ardumont") 155 | '(org2jekyll-source-directory (expand-file-name "~/org/")) 156 | '(org2jekyll-jekyll-directory (expand-file-name "~/repo/public/ardumont.github.io/")) 157 | '(org2jekyll-jekyll-drafts-dir "") 158 | '(org2jekyll-jekyll-posts-dir "_posts/") 159 | '(org-publish-project-alist 160 | `(("default" ;; mostly static pages: about me, about, etc... 161 | :base-directory ,(org2jekyll-input-directory) 162 | :base-extension "org" 163 | :publishing-directory ,(org2jekyll-output-directory) 164 | :publishing-function org-html-publish-to-html 165 | :headline-levels 4 166 | :html-head "" 167 | :html-preamble t 168 | :recursive t 169 | :make-index t 170 | :html-extension "html" 171 | :body-only t) 172 | ("post" ;; dynamic pages like blog articles 173 | :base-directory ,(org2jekyll-input-directory) 174 | :base-extension "org" 175 | :publishing-directory ,(org2jekyll-output-directory org2jekyll-jekyll-posts-dir) 176 | :publishing-function org-html-publish-to-html 177 | :headline-levels 4 178 | :html-head "" 179 | :html-preamble t 180 | :recursive t 181 | :make-index t 182 | :html-extension "html" 183 | :body-only t) 184 | ("images" 185 | :base-directory ,(org2jekyll-input-directory "img") 186 | :base-extension "jpg\\|gif\\|png" 187 | :publishing-directory ,(org2jekyll-output-directory "img") 188 | :publishing-function org-publish-attachment 189 | :recursive t) 190 | ("js" 191 | :base-directory ,(org2jekyll-input-directory "js") 192 | :base-extension "js" 193 | :publishing-directory ,(org2jekyll-output-directory "js") 194 | :publishing-function org-publish-attachment 195 | :recursive t) 196 | ("css" 197 | :base-directory ,(org2jekyll-input-directory "css") 198 | :base-extension "css\\|el" 199 | :publishing-directory ,(org2jekyll-output-directory "css") 200 | :publishing-function org-publish-attachment 201 | :recursive t) 202 | ("web" :components ("images" "js" "css"))))) 203 | #+end_src 204 | source: https://gitlab.com/ardumont/home/-/blob/master/emacs/blog-pack.el#L18-69 205 | 206 | The previous sample contains important information: 207 | - *default* and *post* represent the possible jekyll layouts you can use in 208 | your org2jekyll buffer `#+LAYOUT: default|post` (you can name those 209 | differently, follow [[#layout][the customization layout section]]) 210 | 211 | - *images*, *js*, *css* represent where you choose to store those kinds of 212 | files (you can name these as you wish) 213 | 214 | - *web* is a composition of web files you may need to create a full post or 215 | page, typically, css, images, html, js, etc... (do not name this one 216 | differently either) 217 | 218 | ** A running example 219 | 220 | - blog: [[http://ardumont.github.io/]] 221 | 222 | - jekyll exported source: https://github.com/ardumont/ardumont.github.io 223 | 224 | - the org files: https://github.com/ardumont/org.git 225 | 226 | *Note* Yes, I may have to merge the last 2 repositories at some point... 227 | 228 | ** A reproducible example 229 | 230 | You can clone this repository. Then, try and follow this [[https://github.com/ardumont/org2jekyll/blob/master/testing-blog/org/blogging-with-org2jekyll.org][local article]]. 231 | 232 | * Use 233 | 234 | For a post (layout 'post') or page (layout 'default'), add org headers (layout, 235 | title, author, date, description, categories) to your org files. 236 | 237 | Activate the `org2jekyll-mode` in the buffer you wish to publish: 238 | M-x org2jekyll-mode 239 | 240 | This installs the necessary cogs for org2jekyll to work properly ([[https://github.com/ardumont/org2jekyll/issues/38][issue 38]]). 241 | 242 | ** Post 243 | *** Headers 244 | 245 | For a post (layout 'post'): 246 | #+begin_src org 247 | #+STARTUP: showall 248 | #+STARTUP: hidestars 249 | #+OPTIONS: H:2 num:nil tags:nil toc:nil timestamps:t 250 | #+LAYOUT: post 251 | #+AUTHOR: ardumont 252 | #+DATE: 2014-12-19 Fri 23:49 253 | #+TITLE: hello 254 | #+DESCRIPTION: some description 255 | #+CATEGORIES: category0, category1 256 | #+end_src 257 | 258 | *Note* To easily do that, /M-x org2jekyll-create-draft/, this will ask you for 259 | everything needed and create a file with such metadata. 260 | 261 | *** Publish 262 | 263 | Now write your article in org-mode. 264 | 265 | When ready, /M-x org2jekyll-publish/ to publish it. 266 | 267 | This will be published as post article. 268 | 269 | *** How 270 | 271 | - The *#+LAYOUT* entry refers to the *post* entry in 272 | *org-publish-project-alist*. 273 | 274 | - This will create another temporary org-mode file based on the current one 275 | with the right naming convention, transform the org headers into yaml, 276 | publish to the jekyll directory (according to your org-publish setup) and 277 | delete the temporary file. 278 | 279 | *** Extra headers 280 | 281 | As in [[https://github.com/ardumont/org2jekyll/issues/36][issue 36]], you could [[http://jekyllrb.com/docs/frontmatter/#predefined-global-variables][need to add some extra jekyll headers]]. 282 | 283 | Simply add them as org properties (thanks [[https://github.com/halcyon][@halcyon]] for his work on [[https://github.com/ardumont/org2jekyll/pull/41][#41]]). 284 | 285 | For example, adding those properties in the org file: 286 | #+BEGIN_SRC org 287 | #+THEME: blah 288 | #+PLUGIN: lightense 289 | #+SCHEME-HOVER: "#ff00b4" 290 | #+END_SRC 291 | 292 | Then publishing, will generate: 293 | #+BEGIN_SRC yaml 294 | --- 295 | ... 296 | theme: blah 297 | plugin: lightense 298 | scheme-hover: "#ff00b4" 299 | --- 300 | #+END_SRC 301 | 302 | ** Page 303 | 304 | *** Headers 305 | 306 | For a page (layout 'default'). 307 | 308 | #+begin_src org 309 | #+STARTUP: showall 310 | #+STARTUP: hidestars 311 | #+OPTIONS: H:2 num:nil tags:nil toc:nil timestamps:t 312 | #+LAYOUT: default 313 | #+AUTHOR: ardumont 314 | #+DATE: 2014-12-19 Fri 23:49 315 | #+TITLE: hello 316 | #+DESCRIPTION: some description 317 | #+CATEGORIES: some-category 318 | #+end_src 319 | 320 | *Note* To easily do that, /M-x org2jekyll-create-draft/, this will ask you for 321 | everything needed and create a file with such metadata. 322 | 323 | Now create your article and publish it when ready /M-x org2jekyll-publish/. 324 | 325 | *** Publish 326 | 327 | Write your page. 328 | When ready, /M-x org2jekyll-publish/ to publish it. 329 | 330 | *** How 331 | 332 | - The *#+LAYOUT* entry refers to the *default* entry in 333 | *org-publish-project-alist*. 334 | - This will update the current org-mode with the necessary yaml and publish to 335 | the jekyll directory (according to your org-publish setup), then revert back 336 | to your normal org-mode file. 337 | 338 | *** Extra-headers 339 | 340 | cf. [[#extra-headers][post extra-headers]] 341 | 342 | ** Publish all posts 343 | 344 | /M-x org2jekyll-publish-posts/ 345 | 346 | Depending on your org-publish configuration and org2jekyll, this will compile 347 | the list of org-mode posts (*#+LAYOUT* with 'post' value) and publish them. 348 | 349 | ** Publish all pages 350 | 351 | /M-x org2jekyll-publish-pages/ 352 | 353 | Depending on your org-publish configuration and org2jekyll, this will compile 354 | the list of org-mode pages (*#+LAYOUT* with 'default value) and publish them. 355 | 356 | ** Previews 357 | 358 | You can keep an org file in your blog directory without publishing it, by 359 | writing it as a plain org file without the org2jekyll headers. Once you're 360 | ready to publish it as a post or an article, add the appropriate metadata 361 | headers and org2jekyll will now publish the file. 362 | 363 | * Minor mode 364 | 365 | org2jekyll provides you a minor mode with the following default binding: 366 | #+begin_src emacs-lisp 367 | (setq org2jekyll-mode-map 368 | (let ((map (make-sparse-keymap))) 369 | (define-key map (kbd "C-c . n") 'org2jekyll-create-draft) 370 | (define-key map (kbd "C-c . p") 'org2jekyll-publish-post) 371 | (define-key map (kbd "C-c . P") 'org2jekyll-publish-posts) 372 | (define-key map (kbd "C-c . l") 'org2jekyll-list-posts) 373 | (define-key map (kbd "C-c . d") 'org2jekyll-list-drafts) 374 | map)) 375 | #+end_src 376 | 377 | *Note* [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Key-Binding-Conventions.html#Key-Binding-Conventions][Respecting the default minor mode convention for binding]] 378 | 379 | To (de)activate this in an org file: /M-x org2jekyll-mode/ 380 | 381 | As usual, you can use emacs' power to setup your own bindings. 382 | 383 | * Customization 384 | 385 | ** Layout 386 | By default org2jekyll uses the layouts "post" (for article blog post) and 387 | "default" (for mostly dynamic pages, e.g. contact, about, ...). This now can be 388 | customized: 389 | 390 | #+BEGIN_SRC sh 391 | (custom-set-variables 392 | '(org2jekyll-jekyll-layout-page "page") 393 | '(org2jekyll-jekyll-layout-post "post") 394 | '(org2jekyll-jekyll-layouts '("page" "post"))) 395 | #+END_SRC 396 | 397 | It's up to the users to make sure the entries are correctly configured in the 398 | `org-publish-project-alist`. 399 | 400 | See for example [[https://github.com/ardumont/org2jekyll/blob/master/testing-blog/testing-blog-config.el][this sample configuration]] which define their own while keeping 401 | correctly the `org-publish-project-alist` in sync. 402 | 403 | ** Draft 404 | 405 | By default, a draft has a fixed set of headers. It is now possible to configure 406 | extra set of headers (with fixed values). 407 | 408 | To answer, for example, [[https://github.com/ardumont/org2jekyll/issues/47][issue 47 need]], a user could define the following: 409 | 410 | #+BEGIN_SRC emacs-lisp 411 | (custom-set-variables 412 | '(org2jekyll-default-template-entries-extra '(("comments" "true") ("theme" "awesome"))) 413 | #+END_SRC 414 | 415 | Which would then append the `#+COMMENTS: true` and `#+THEME: awesome` to the 416 | default template org2jekyll generates by default. All following created drafts 417 | would be created with that extra comments headers. 418 | 419 | * About internal publication links 420 | 421 | You can now link properly between your jekyll publications. You need however to 422 | prefix your local links with the `local:` prefix. 423 | 424 | For example: 425 | #+BEGIN_SRC org 426 | [[local:/interesting-post]] 427 | #+END_SRC 428 | 429 | will render into a proper html `a` anchor linking to your interesting post. See 430 | [[https://github.com/ardumont/org2jekyll/issues/66][#66 issue for more details]]. 431 | 432 | * Problems 433 | ** dependencies 434 | 435 | As a note, org2jekyll [[https://github.com/ardumont/org2jekyll/blob/master/org2jekyll.el#L8][declares its dependencies]] but it's possible that 436 | some are not fully respected. And then problem [[#43][may arise]]. So if you 437 | found out a problem about it, feel free to open an issue mentioning 438 | the version of the library you are using. 439 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /org2jekyll.el: -------------------------------------------------------------------------------- 1 | ;;; org2jekyll.el --- Minor mode to publish org-mode post to jekyll without specific yaml 2 | 3 | ;; Copyright (C) 2014-2020 Antoine R. Dumont (@ardumont) 4 | 5 | ;; Author: Antoine R. Dumont (@ardumont) 6 | ;; Maintainer: Antoine R. Dumont (@ardumont) 7 | ;; Version: 0.2.7 8 | ;; Package-Requires: ((dash "2.18.0") (s "1.9.0")) 9 | ;; Keywords: org-mode jekyll blog publish 10 | ;; URL: https://github.com/ardumont/org2jekyll 11 | 12 | ;; This file is NOT part of GNU Emacs. 13 | 14 | ;; This program is free software; you can redistribute it and/or modify 15 | ;; it under the terms of the GNU General Public License as published by 16 | ;; the Free Software Foundation; either version 3, or (at your option) 17 | ;; any later version. 18 | ;; 19 | ;; This program is distributed in the hope that it will be useful, 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | ;; GNU General Public License for more details. 23 | ;; 24 | ;; You should have received a copy of the GNU General Public License 25 | ;; along with GNU Emacs; see the file COPYING. If not, write to the 26 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 27 | ;; Boston, MA 02110-1301, USA. 28 | 29 | ;;; Commentary: 30 | 31 | ;; Functions to ease publishing jekyll posts from org-mode file 32 | 33 | ;; Providing you have a working `'jekyll`' and `'org-publish`' 34 | ;; This will permit you to simply export an org-mode file with the right jekyll 35 | ;; format to the right folder 36 | ;; 37 | ;; M-x org2jekyll-create-draft create a draft with the necessary metadata 38 | ;; 39 | ;; M-x org2jekyll-publish publish the current post (or page) to the jekyll folder 40 | ;; 41 | ;; M-x org2jekyll-publish-pages to publish all pages (layout 'default') 42 | ;; 43 | ;; M-x org2jekyll-publish-posts to publish all post pages (layout 'post') 44 | ;; 45 | ;; M-x org2jekyll-mode to activate org2jekyll's minor mode 46 | ;; 47 | ;; You can customize using M-x customize-group RET org2jekyll RET 48 | ;; 49 | ;; More information on https://github.com/ardumont/org2jekyll 50 | 51 | ;;; Code: 52 | 53 | (require 'org) 54 | (require (if (version< emacs-version "24.4") 'org-publish 'ox-publish)) 55 | 56 | (require 'dash) 57 | (require 's) 58 | (require 'ido) 59 | 60 | (defconst org2jekyll--version "0.2.7" "Current org2jekyll version installed.") 61 | 62 | (defgroup org2jekyll nil "Publish org-mode posts to jekyll" 63 | :tag "org2jekyll" 64 | :version "0.0.3" 65 | :group 'org) 66 | 67 | (defcustom org2jekyll-blog-author nil 68 | "Blog entry author." 69 | :type 'string 70 | :require 'org2jekyll 71 | :group 'org2jekyll) 72 | 73 | (defcustom org2jekyll-source-directory nil 74 | "Path to the source directory." 75 | :type 'string 76 | :require 'org2jekyll 77 | :group 'org2jekyll) 78 | 79 | (defcustom org2jekyll-jekyll-directory nil 80 | "Path to Jekyll blog." 81 | :type 'string 82 | :require 'org2jekyll 83 | :group 'org2jekyll) 84 | 85 | (defcustom org2jekyll-jekyll-drafts-dir nil 86 | "Path to drafts directory relative to `org2jekyll-jekyll-directory`." 87 | :type 'string 88 | :require 'org2jekyll 89 | :group 'org2jekyll) 90 | 91 | (defcustom org2jekyll-jekyll-posts-dir nil 92 | "Path to posts directory relative to `org2jekyll-jekyll-directory`." 93 | :type 'string 94 | :require 'org2jekyll 95 | :group 'org2jekyll) 96 | 97 | (defcustom org2jekyll-jekyll-layouts '("post" "default") 98 | "Possible layouts, by default either a post or a page" 99 | :type 'string 100 | :require 'org2jekyll 101 | :group 'org2jekyll) 102 | 103 | (defcustom org2jekyll-jekyll-layout-post "post" 104 | "Article blog post layout" 105 | :type 'string 106 | :require 'org2jekyll 107 | :group 'org2jekyll) 108 | 109 | (defcustom org2jekyll-jekyll-layout-page "default" 110 | "Article page layout, mostly intended as static pages (e.g about, contacts, etc...)" 111 | :type 'string 112 | :require 'org2jekyll 113 | :group 'org2jekyll) 114 | 115 | (defvar org2jekyll-default-template-entries 116 | '(("startup" "showall") 117 | ("startup" "hidestars") 118 | ("options" "H:2 num:nil tags:t toc:nil timestamps:t") 119 | ("layout") 120 | ("author") 121 | ("date") 122 | ("title") 123 | ("description") 124 | ("tags") 125 | ("categories")) 126 | "Default list of tuple '( ). 127 | Optionally a tuple could be in the form '(). 128 | Its values are initialized according to the values defined in version <= 0.2.2.") 129 | 130 | (defun org2jekyll--header-entry (header-entry) 131 | "Given a HEADER-ENTRY, format string as org-mode header." 132 | (let ((header-name (-> header-entry car s-upcase)) 133 | (header-value (-if-let (val (cadr header-entry)) val "%s"))) 134 | (format "#+%s: %s" header-name header-value))) 135 | 136 | (defun org2jekyll--inline-headers (tuple-entries) 137 | "Given TUPLE-ENTRIES, format as org-mode headers." 138 | (->> tuple-entries 139 | (mapcar 'org2jekyll--header-entry) 140 | (s-join "\n") 141 | (format "%s\n\n"))) 142 | 143 | (defcustom org2jekyll-default-template-entries-extra nil 144 | "Allow users to define extra template headers entries." 145 | :type 'alist) 146 | 147 | (defvar org2jekyll-jekyll-post-ext ".org" 148 | "File extension of Jekyll posts.") 149 | 150 | (defun org2jekyll--optional-folder (folder-source &optional folder-name) 151 | "Compute the folder name from a FOLDER-SOURCE and an optional FOLDER-NAME." 152 | (format "%s/%s" folder-source (if folder-name folder-name ""))) 153 | 154 | ;;;###autoload 155 | (defun org2jekyll-input-directory (&optional folder-name) 156 | "Compute the input folder from the FOLDER-NAME." 157 | (org2jekyll--optional-folder org2jekyll-source-directory folder-name)) 158 | 159 | ;;;###autoload 160 | (defun org2jekyll-output-directory (&optional folder-name) 161 | "Compute the output folder from the optional FOLDER-NAME." 162 | (org2jekyll--optional-folder org2jekyll-jekyll-directory folder-name)) 163 | 164 | (defun org2jekyll--make-slug (s) 165 | "Turn a string S into a slug." 166 | (->> s 167 | (replace-regexp-in-string "[\]\[(){}!#$~^\\]" "") 168 | downcase 169 | (replace-regexp-in-string " " "-"))) 170 | 171 | (defun org2jekyll--yaml-escape (s) 172 | "Escape a string S for YAML." 173 | (if (or (string-match ":" s) 174 | (string-match "\"" s)) 175 | (concat "\"" (replace-regexp-in-string "\"" "\\\\\"" s) "\"") 176 | s)) 177 | 178 | (defun org2jekyll-now () 179 | "Generate a formatted now date." 180 | (format-time-string "%Y-%m-%d %a %H:%M")) 181 | 182 | (defun org2jekyll-default-headers-template (headers) 183 | "Return an org metadata string with entries in HEADERS." 184 | (mapconcat #'org2jekyll--header-entry headers "\n")) 185 | 186 | (defun org2jekyll--draft-filename (draft-dir title) 187 | "Compute the draft's filename from the DRAFT-DIR and TITLE." 188 | (concat draft-dir (org2jekyll--make-slug title) org2jekyll-jekyll-post-ext)) 189 | 190 | (defun org2jekyll--read-title () 191 | "Read the title." 192 | (read-string "Title: ")) 193 | 194 | (defun org2jekyll--read-description () 195 | "Read the description." 196 | (read-string "Description: ")) 197 | 198 | (defun org2jekyll--read-tags () 199 | "Read the tags." 200 | (read-string "Tags (space separated values): ")) 201 | 202 | (defun org2jekyll--read-categories () 203 | "Read the categories." 204 | (read-string "Categories (space separated values): ")) 205 | 206 | (defun org2jekyll--input-read (prompt collection) 207 | "Input PROMPT with possibilities limited to COLLECTION." 208 | (ido-completing-read prompt 209 | collection 210 | nil 211 | 'require-match)) 212 | 213 | (defun org2jekyll--init-buffer-metadata (&optional ignore-plist) 214 | "Return an plist holding buffer metadata information collected from the user. 215 | Any non-nil property in IGNORE-PLIST will not be collected from the user, and 216 | will instead have its value omitted in the returned plist." 217 | (-concat (unless (plist-get ignore-plist :author) 218 | (list :author org2jekyll-blog-author)) 219 | (unless (plist-get ignore-plist :date) 220 | (list :date (org2jekyll-now))) 221 | (unless (plist-get ignore-plist :layout) 222 | (list :layout (org2jekyll--input-read "Layout: " org2jekyll-jekyll-layouts))) 223 | (unless (plist-get ignore-plist :title) 224 | (list :title (org2jekyll--read-title))) 225 | (unless (plist-get ignore-plist :description) 226 | (list :description (org2jekyll--read-description))) 227 | (unless (plist-get ignore-plist :tags) 228 | (list :tags (org2jekyll--read-tags))) 229 | (unless (plist-get ignore-plist :categories) 230 | (list :categories (org2jekyll--read-categories))))) 231 | 232 | (defun org2jekyll--get-template-entries (&optional decided-options-alist) 233 | "Return the contents of org2jekyll-default-template-entries and org2jekyll-default-template-entries-extra replaced by entries is DECIDED-OPTIONS-ALIST." 234 | (let ((-compare-fn #'string=) 235 | (decided-options (-map #'car decided-options-alist))) 236 | (--map-when (and (not (cdr it)) (-contains? decided-options (car it))) 237 | (-first (lambda (option) (string= (car it) (car option))) 238 | decided-options-alist) 239 | (-concat org2jekyll-default-template-entries 240 | org2jekyll-default-template-entries-extra)))) 241 | 242 | (defun org2jekyll--get-filtered-entries (entries ignore-list) 243 | "Return a list from ENTRIES whose car is not present in IGNORE-LIST." 244 | (let ((-compare-fn #'string=)) 245 | (--filter (not (-contains? ignore-list (car it))) entries))) 246 | 247 | ;;;###autoload 248 | (defun org2jekyll-init-current-buffer () 249 | "Given an existing buffer, add the needed metadata to make it a post or page." 250 | (interactive) 251 | (let* ((existing-options-plist (org2jekyll-get-options-from-buffer)) 252 | (existing-options-alist (org2jekyll--plist-to-alist existing-options-plist)) 253 | (metadata (org2jekyll--plist-to-alist 254 | (org2jekyll--init-buffer-metadata existing-options-plist))) 255 | ;; Drop options known to already be in the buffer 256 | (ignore-list (-map #'car existing-options-alist)) 257 | (add-to-file-options (org2jekyll--get-filtered-entries 258 | (org2jekyll--get-template-entries metadata) ignore-list)) 259 | (add-to-file-tuples (org2jekyll--alist-to-tuples add-to-file-options))) 260 | (save-excursion 261 | (with-current-buffer (buffer-name) 262 | (goto-char (point-min)) 263 | (let* ((no-options (length existing-options-alist)) 264 | (non-metadata-present-p (> (count-lines (point-min) (point-max)) 265 | no-options))) 266 | ;; Ensure we insert after any existing options 267 | (forward-line (length existing-options-alist)) 268 | ;; If the buffer ends at the end of existing options, insert a new line 269 | (when (and (> no-options 0) (not (char-equal ?\n (char-before)))) 270 | (insert "\n")) 271 | (insert (org2jekyll-default-headers-template add-to-file-tuples) "\n") 272 | ;; Create line between metadata and non-metadata if non-metadata exists 273 | (when (and (= no-options 0) non-metadata-present-p) (insert "\n"))))))) 274 | 275 | ;;;###autoload 276 | (defun org2jekyll-create-draft () 277 | "Prompt the user for org metadata and then create a new Jekyll blog post. 278 | The specified title will be used as the name of the file." 279 | (interactive) 280 | (let* ((metadata (org2jekyll--init-buffer-metadata)) 281 | (metadata-alist (org2jekyll--plist-to-alist metadata)) 282 | (title (plist-get metadata :title)) 283 | (draft-file (org2jekyll--draft-filename 284 | (org2jekyll-input-directory org2jekyll-jekyll-drafts-dir) 285 | title)) 286 | (add-to-file-options (org2jekyll--get-template-entries metadata-alist)) 287 | (add-to-file-tuples (org2jekyll--alist-to-tuples add-to-file-options))) 288 | (unless (file-exists-p draft-file) 289 | (with-temp-file draft-file 290 | (insert (org2jekyll-default-headers-template add-to-file-tuples) "\n\n") 291 | (insert "* "))) 292 | (find-file draft-file))) 293 | 294 | (defun org2jekyll--list-dir (dir) 295 | "List the content of DIR." 296 | (find-file dir)) 297 | 298 | ;;;###autoload 299 | (defun org2jekyll-list-posts () 300 | "Lists the posts folder." 301 | (interactive) 302 | (org2jekyll--list-dir 303 | (org2jekyll-output-directory org2jekyll-jekyll-posts-dir))) 304 | 305 | ;;;###autoload 306 | (defun org2jekyll-list-drafts () 307 | "List the drafts folder." 308 | (interactive) 309 | (org2jekyll--list-dir 310 | (org2jekyll-input-directory org2jekyll-jekyll-drafts-dir))) 311 | 312 | (defun org2jekyll-get-options-from-buffer () 313 | "Return special lines at the beginning of current buffer." 314 | (let ((special-line-regex "^#\\+\\(.+\\):[ \t]+\\(.*\\)$") 315 | (get-current-line (lambda () 316 | (buffer-substring-no-properties (line-beginning-position) 317 | (line-end-position)))) 318 | (options-plist)) 319 | (save-excursion 320 | (goto-char (point-min)) 321 | (catch 'break 322 | (while (string-match special-line-regex (funcall get-current-line)) 323 | (let ((current-line (funcall get-current-line))) 324 | (unless (s-blank-str-p (match-string 2 current-line)) 325 | (setq options-plist (plist-put options-plist 326 | (->> current-line 327 | (match-string 1) 328 | downcase 329 | (concat ":") 330 | intern) 331 | (match-string 2 current-line))))) 332 | (unless (= 0 (forward-line)) 333 | (throw 'break nil)))) 334 | options-plist))) 335 | 336 | (defun org2jekyll--without-option-p (option &optional options) 337 | "Determine if OPTION needs to be deactivated amongst options." 338 | ;; FIXME: Find the proper org implementation call ¯\_(ツ)_/¯ 339 | (let ((properties (-> (if options options (org2jekyll-get-options-from-buffer)) 340 | (plist-get :options)))) 341 | (when properties 342 | (let ((off-option (format "%s:nil" option))) 343 | (->> properties 344 | (s-split " ") 345 | (--filter (string= off-option it))))))) 346 | 347 | (defun org2jekyll--with-tags-p (options) 348 | "Determine, from OPTIONS if we need to export in yaml the tags options" 349 | (-> "tags" 350 | (org2jekyll--without-option-p options) 351 | not)) 352 | 353 | (defun org2jekyll-get-options-from-file (orgfile) 354 | "Return special lines at the beginning of ORGFILE." 355 | (with-temp-buffer 356 | (when (file-exists-p orgfile) 357 | (insert-file-contents orgfile) 358 | (org2jekyll-get-options-from-buffer)))) 359 | 360 | (defun org2jekyll-article-p (org-file) 361 | "Determine if the current ORG-FILE's layout. 362 | Depends on the metadata header #+LAYOUT." 363 | (plist-get (org2jekyll-get-options-from-file org-file) :layout)) 364 | 365 | (defun org2jekyll--org-to-jekyll-metadata (org-metadata) 366 | "Given an ORG-METADATA map, translate Org keywords to Jekyll keywords." 367 | (let ((org2jekyll-map-keys '(("description" . "excerpt")))) 368 | (--map (-if-let (jekyll-car (assoc-default (car it) org2jekyll-map-keys)) 369 | (cons jekyll-car (cdr it)) 370 | it) 371 | org-metadata))) 372 | 373 | (defun org2jekyll--convert-timestamp-to-yyyy-dd-mm-hh (timestamp) 374 | "Convert org TIMESTAMP to YYYY-MM-DD HH:MM. For yaml header purposes." 375 | (format-time-string "%Y-%m-%d %H:%M" 376 | (apply 'encode-time (org-parse-time-string timestamp)))) 377 | 378 | (defun org2jekyll--convert-timestamp-to-yyyy-dd-mm (timestamp) 379 | "Convert org TIMESTAMP to to YYYY-MM-DD. For filename renaming purposes." 380 | (format-time-string "%Y-%m-%d" 381 | (apply 'encode-time (org-parse-time-string timestamp)))) 382 | 383 | (defun org2jekyll--to-yaml-header (org-metadata) 384 | "Given a list of ORG-METADATA, compute the yaml header string." 385 | (--> (org2jekyll--org-to-jekyll-metadata org-metadata) 386 | (--map (format "%s: %s" (car it) (cdr it)) it) 387 | (cons "---" it) 388 | (-snoc it "---\n") 389 | (s-join "\n" it))) 390 | 391 | (defun org2jekyll--space-separated-values-to-yaml (str) 392 | "Transform a STR of space separated values entries into yaml entries." 393 | (->> (if str str "") 394 | (s-split " ") 395 | (--filter (unless (equal it "") it)) 396 | (--map (format "- %s" it)) 397 | (cons "") 398 | (s-join "\n"))) 399 | 400 | (defun org2jekyll--compute-ready-jekyll-file-name (date org-file) 401 | "Given a DATE and an ORG-FILE, compute a ready jekyll file name. 402 | If the current path contains the `'org2jekyll-jekyll-drafts-dir`', removes it." 403 | (let* ((temp-org-jekyll-filename (format "%s-%s" date 404 | (file-name-nondirectory org-file)))) 405 | (->> temp-org-jekyll-filename 406 | (format "%s/%s" org2jekyll-source-directory) 407 | (replace-regexp-in-string (format "%s" org2jekyll-jekyll-drafts-dir) "") 408 | (replace-regexp-in-string "//" "/")))) 409 | 410 | (defconst org2jekyll-required-org-header-alist '((:title . 'required) 411 | (:date) 412 | (:categories . 'required) 413 | (:tags) 414 | (:description . 'required) 415 | (:author) 416 | (:layout . 'required)) 417 | "Map of required org headers for jekyll to accept rendering.") 418 | 419 | (defun org2jekyll-check-metadata (org-metadata) 420 | "Check that all required headers in ORG-METADATA are provided. 421 | Return error messages for any required headers that are missing, 422 | and nil if no problems are found." 423 | (let ((required-options (funcall (-compose (lambda (l) (mapcar #'car l)) 424 | (lambda (l) (-filter #'cdr l))) 425 | org2jekyll-required-org-header-alist))) 426 | (-when-let (error-messages 427 | (->> required-options 428 | (--map (unless (plist-member org-metadata it) 429 | (format (concat "- The %s is required, please add " 430 | "'#+%s' at the top of your org buffer.") 431 | (substring (symbol-name it) 1 nil) 432 | (upcase (substring (symbol-name it) 1 nil))))) 433 | (s-join "\n") 434 | s-trim)) 435 | (if (string= "" error-messages) nil error-messages)))) 436 | 437 | (defun org2jekyll--symbol-to-string (symbol) 438 | "Make a string out of a SYMBOL. 439 | symbol is of the form ':'" 440 | (let ((s (if (stringp symbol) symbol (symbol-name symbol)))) 441 | (substring s 1 nil))) 442 | 443 | (defun org2jekyll--plist-to-alist (plist) 444 | "Make an alist out of a PLIST." 445 | (--map 446 | (let ((key (-> it 447 | car 448 | org2jekyll--symbol-to-string)) 449 | (value (cadr it))) 450 | `(,key . ,value)) 451 | (-partition 2 plist))) 452 | 453 | (defun org2jekyll--alist-to-tuples (alist) 454 | "Return a list of tuples with values from ALIST. 455 | Any values for which -cons-pair? returns nil are left unchanged." 456 | (--map (cond 457 | ((and (-cons-pair? it) (cdr it)) (list (car it) (cdr it))) 458 | (t it)) 459 | alist)) 460 | 461 | (defun org2jekyll-remove-org-only-options (yaml-alist) 462 | "Filter out org options with no Jekyll meaning from YAML-ALIST." 463 | (let* ((required-options (--map (-> it car org2jekyll--symbol-to-string) 464 | org2jekyll-required-org-header-alist)) 465 | (org-options (--map (downcase (substring it 0 -1)) 466 | org-options-keywords)) 467 | (org-only-options (--filter (not (member it required-options)) 468 | org-options)) 469 | (jekyll-options (--filter (not (member (car it) org-only-options)) 470 | yaml-alist))) 471 | jekyll-options)) 472 | 473 | (defun org2jekyll-read-metadata (org-file) 474 | "Given an ORG-FILE, return its org metadata. 475 | It can display an error message about missing required values." 476 | (let* ((buffer-metadata (org2jekyll-get-options-from-file org-file))) 477 | (-if-let (error-messages (org2jekyll-check-metadata buffer-metadata)) 478 | (format "This org-mode file is missing required header(s): 479 | %s 480 | Publication skipped" error-messages) 481 | (let* ((org-defaults `(:date ,(org2jekyll-now) :author "")) 482 | (merged-metadata (org-combine-plists org-defaults buffer-metadata)) 483 | (categories (org2jekyll--space-separated-values-to-yaml 484 | (plist-get merged-metadata :categories))) 485 | (tags (if (org2jekyll--with-tags-p buffer-metadata) 486 | (org2jekyll--space-separated-values-to-yaml 487 | (plist-get merged-metadata :tags)) 488 | "")) 489 | (date (org2jekyll--convert-timestamp-to-yyyy-dd-mm-hh 490 | (plist-get merged-metadata :date))) 491 | (yaml-metadata (-> merged-metadata 492 | (plist-put :categories categories) 493 | (plist-put :tags tags) 494 | (plist-put :date date))) 495 | (yaml-alist (org2jekyll--plist-to-alist yaml-metadata))) 496 | (org2jekyll-remove-org-only-options yaml-alist))))) 497 | 498 | (defun org2jekyll-read-metadata-and-execute (action-fn org-file) 499 | "Execute ACTION-FN function after checking metadata from the ORG-FILE." 500 | (let ((filename-non-dir (file-name-nondirectory org-file))) 501 | (if (org2jekyll-article-p org-file) 502 | (let ((org-metadata (org2jekyll-read-metadata org-file))) 503 | (if (stringp org-metadata) 504 | (org2jekyll-message org-metadata) 505 | (let ((page-or-post (if (org2jekyll-post-p 506 | (assoc-default "layout" org-metadata)) 507 | "Post" 508 | "Page"))) 509 | (funcall action-fn org-metadata org-file) 510 | (format "%s '%s' published!" page-or-post filename-non-dir)))) 511 | (format "'%s' is not an article, publication skipped!" filename-non-dir)))) 512 | 513 | (defun org2jekyll-message (&rest args) 514 | "Log formatted ARGS." 515 | (apply 'message (format "org2jekyll - %s" (car args)) (cdr args))) 516 | 517 | (defun org2jekyll--publish-temp-file-then-cleanup (org-file temp-file project) 518 | "Publish ORG-FILE using TEMP-FILE (with yaml header) using PROJECT metadata." 519 | (copy-file org-file temp-file 'overwrite 'keep-time 'preserve-ids 'preserve-perms) 520 | (with-temp-file temp-file 521 | ;; activate org2jekyll-mode to rely on its hook to work properly 522 | (org2jekyll-mode) 523 | (org-publish-file temp-file project)) 524 | ;; the org2jekyll installed hook should have kicked-in already, if it remains 525 | ;; dangling temporary file, just delete it 526 | (when (file-exists-p temp-file) 527 | (delete-file temp-file))) 528 | 529 | (defun org2jekyll--publish-post-org-file-with-metadata (org-metadata org-file) 530 | "Publish as post with ORG-METADATA the ORG-FILE." 531 | (let* ((project (-> "layout" 532 | (assoc-default org-metadata) ;; layout is the blog-project 533 | (assoc org-publish-project-alist))) 534 | (file-date (-> (assoc-default "date" org-metadata) 535 | org2jekyll--convert-timestamp-to-yyyy-dd-mm)) 536 | (temp-file (org2jekyll--compute-ready-jekyll-file-name file-date org-file))) 537 | (org2jekyll--publish-temp-file-then-cleanup org-file temp-file project))) 538 | 539 | (defun org2jekyll-publish-post (org-file) 540 | "Publish ORG-FILE as a post." 541 | (org2jekyll-read-metadata-and-execute 542 | 'org2jekyll--publish-post-org-file-with-metadata 543 | org-file)) 544 | 545 | (defun org2jekyll-install-yaml-headers (original-file published-file) 546 | "Read ORIGINAL-FILE metadata and install yaml header to PUBLISHED-FILE. 547 | Then delete the original-file which is intended as a temporary file. 548 | Only for org-mode file, for other files, it's a noop. 549 | This function is intended to be used as org-publish hook function." 550 | (let ((original-file-ext (file-name-extension original-file)) 551 | (published-file-ext (file-name-extension published-file))) 552 | ;; original-file is the temporary file generated which will be edited with 553 | ;; jekyll's yaml headers 554 | 555 | ;; careful about extensions: "post" -> org ; page -> org2jekyll 556 | ;; other stuff are considered neither, so it's a noop 557 | (when (and (or (string= "org" original-file-ext) (string= "org2jekyll" original-file-ext)) 558 | (string= "html" published-file-ext)) 559 | (let ((yaml-headers (-> original-file 560 | org2jekyll-read-metadata 561 | org2jekyll--to-yaml-header))) 562 | (with-temp-file published-file 563 | (insert-file-contents published-file) 564 | (goto-char (point-min)) 565 | (insert yaml-headers)) 566 | (delete-file original-file))))) 567 | 568 | (defun org2jekyll--publish-page-org-file-with-metadata (org-metadata org-file) 569 | "Publish as page with ORG-METADATA the ORG-FILE." 570 | (let* ((project (-> "layout" 571 | (assoc-default org-metadata) ;; layout is the blog-project 572 | (assoc org-publish-project-alist))) 573 | (filename (file-name-nondirectory org-file)) 574 | (ext (file-name-extension filename)) 575 | (temp-file (format "%s/%sorg2jekyll" 576 | (s-chop-suffix "/" org2jekyll-source-directory) 577 | (s-chop-suffix ext filename)))) 578 | (org2jekyll--publish-temp-file-then-cleanup org-file temp-file project))) 579 | 580 | (defun org2jekyll-publish-page (org-file) 581 | "Publish ORG-FILE as a page." 582 | (org2jekyll-read-metadata-and-execute 583 | 'org2jekyll--publish-page-org-file-with-metadata 584 | org-file)) 585 | 586 | (defun org2jekyll-post-p (layout) 587 | "Determine if the LAYOUT corresponds to a post." 588 | (string= org2jekyll-jekyll-layout-post layout)) 589 | 590 | (defun org2jekyll-page-p (layout) 591 | "Determine if the LAYOUT corresponds to a page." 592 | (string= org2jekyll-jekyll-layout-page layout)) 593 | 594 | (defun org2jekyll-publish-web-project () 595 | "Publish the 'web' project." 596 | (let ((result (org-publish-project "web"))) 597 | (org2jekyll-message "Publish `'web`' project (images, css, js, etc...) done.") 598 | result)) 599 | 600 | ;;;###autoload 601 | (defun org2jekyll-publish () 602 | "Publish the current org file as post or page depending on the chosen layout. 603 | Layout `'post`' is a jekyll post. 604 | Layout `'default`' is a page (depending on the user customs)." 605 | (interactive) 606 | (let* ((buffer (current-buffer)) 607 | (org-file (buffer-file-name buffer)) 608 | (org-options (with-current-buffer buffer (org2jekyll-get-options-from-buffer))) 609 | (publish-fn (-> (plist-get org-options :layout) 610 | org2jekyll-post-p 611 | (if 'org2jekyll-publish-post 612 | 'org2jekyll-publish-page))) 613 | (final-message (funcall publish-fn org-file))) 614 | (progn 615 | (org2jekyll-publish-web-project) 616 | (org2jekyll-message final-message)))) 617 | 618 | (defvar org2jekyll-mode-map nil "Default Bindings map for org2jekyll mode.") 619 | 620 | (setq org2jekyll-mode-map 621 | (let ((map (make-sparse-keymap))) 622 | (define-key map (kbd "C-c . n") 'org2jekyll-create-draft) 623 | (define-key map (kbd "C-c . p") 'org2jekyll-publish) 624 | (define-key map (kbd "C-c . P") 'org2jekyll-publish-posts) 625 | (define-key map (kbd "C-c . l") 'org2jekyll-list-posts) 626 | (define-key map (kbd "C-c . d") 'org2jekyll-list-drafts) 627 | map)) 628 | 629 | ;;;###autoload 630 | (defun org2jekyll-publish-posts () 631 | "Publish all posts." 632 | (interactive) 633 | (->> (assoc org2jekyll-jekyll-layout-post org-publish-project-alist) 634 | org-publish-get-base-files 635 | (--filter (-> it org2jekyll-article-p org2jekyll-post-p)) 636 | (mapc #'org2jekyll-publish-post))) 637 | 638 | ;;;###autoload 639 | (defun org2jekyll-publish-pages () 640 | "Publish all pages." 641 | (interactive) 642 | (->> (assoc org2jekyll-jekyll-layout-page org-publish-project-alist) 643 | org-publish-get-base-files 644 | (--filter (-> it org2jekyll-article-p org2jekyll-page-p)) 645 | (mapc #'org2jekyll-publish-page))) 646 | 647 | (defun org2jekyll-version () 648 | "Little version helper" 649 | (interactive) 650 | (let ((version org2jekyll--version)) 651 | (message "org2jekyll-version: %s" version) 652 | version)) 653 | 654 | (defun org2jekyll--bug-report () 655 | "Compute the bug report for the user to include." 656 | (->> `("Please:" 657 | "- Describe your problem with clarity and conciceness (cf. https://www.gnu.org/software/emacs/manual/html_node/emacs/Understanding-Bug-Reporting.html)" 658 | "- Explicit your installation choice (melpa, marmalade, el-get, tarball, git clone...)." 659 | "- A sample of your configuration." 660 | "- Report the following message trace inside your issue." 661 | "" 662 | "System information:" 663 | ,(format "- system-type: %s" system-type) 664 | ,(format "- locale-coding-system: %s" locale-coding-system) 665 | ,(format "- emacs-version: %s" (emacs-version)) 666 | ,(format "- org version: %s" (org-version)) 667 | ,(format "- org2jekyll version: %s" org2jekyll--version) 668 | ,(format "- org2jekyll path: %s" (find-library-name "org2jekyll"))) 669 | (s-join "\n"))) 670 | 671 | (defun org2jekyll-bug-report (&optional open-url) 672 | "Display a bug report message. 673 | When OPEN-URL is filled, with universal argument (`C-u') is used, 674 | opens new issue in org-trello's github tracker." 675 | (interactive "P") 676 | (when open-url 677 | (browse-url "https://github.com/ardumont/org2jekyll/issues/new")) 678 | (message (org2jekyll--bug-report))) 679 | 680 | 681 | ;;;###autoload 682 | (define-minor-mode org2jekyll-mode 683 | "Functionality for publishing the current org-mode post to jekyll. 684 | With no argument, the mode is toggled on/off. 685 | Non-nil argument turns mode on. 686 | Nil argument turns mode off. 687 | 688 | Commands: 689 | \\{org2jekyll-mode-map}" 690 | 691 | :init-value nil 692 | :lighter " o2j" 693 | :group 'org2jekyll 694 | :keymap org2jekyll-mode-map) 695 | 696 | ;; install/uninstall hook when activating/deactivating org2jekyll-mode 697 | ;; org2jekyll inserts the yaml when the publishing step is done, so now org 698 | ;; does all the publishing in concordance to what the user expects and we do 699 | ;; our update after it so Jekyll is happy. 700 | 701 | (defvar org2jekyll-mode-on-hook nil "org2jekyll starting hook") 702 | (setq org2jekyll-mode-off-hook nil) ;; for dev 703 | ;; install org2jekyll hook in org-publish when activating org2jekyll-mode 704 | (add-hook 'org2jekyll-mode-on-hook 705 | (lambda () 706 | (add-hook 'org-publish-after-publishing-hook 'org2jekyll-install-yaml-headers))) 707 | 708 | (defvar org2jekyll-mode-off-hook '() "org2jekyll stoping hook") 709 | (setq org2jekyll-mode-off-hook nil) ;; for dev 710 | ;; uninstall hook on org-publish 711 | (add-hook 'org2jekyll-mode-off-hook 712 | (lambda () (remove-hook 'org-publish-after-publishing-hook 'org2jekyll-install-yaml-headers))) 713 | 714 | ;; Extend org-mode hyperlinks policy with a "local" link so we can publish 715 | ;; internal links which are then browsable when published 716 | ;; https://orgmode.org/manual/Adding-Hyperlink-Types.html#Adding-Hyperlink-Types 717 | 718 | ;; register new local links so org-mode exports them as is 719 | (org-link-set-parameters "local" :export #'org2jekyll-local-link-export) 720 | 721 | (defun org2jekyll-local-link-export (link description format) 722 | "Export a man page link from Org files." 723 | (let ((desc (or description link))) 724 | (if (string= format "html") 725 | (format "%s" link desc) 726 | (org2jekyll-message "Unknown format %s, only dealing with html" format)))) 727 | 728 | (provide 'org2jekyll) 729 | ;;; org2jekyll.el ends here 730 | -------------------------------------------------------------------------------- /testing-blog/gemset.nix: -------------------------------------------------------------------------------- 1 | { 2 | activesupport = { 3 | dependencies = ["concurrent-ruby" "i18n" "minitest" "tzinfo" "zeitwerk"]; 4 | groups = ["default" "jekyll_plugins"]; 5 | platforms = []; 6 | source = { 7 | remotes = ["https://rubygems.org"]; 8 | sha256 = "1ldrpgy4gfqykzavgdp0svsm41hkzfi2aaq8as9lqd0sq19mgpqx"; 9 | type = "gem"; 10 | }; 11 | version = "6.0.4.1"; 12 | }; 13 | addressable = { 14 | dependencies = ["public_suffix"]; 15 | groups = ["default" "jekyll_plugins"]; 16 | platforms = []; 17 | source = { 18 | remotes = ["https://rubygems.org"]; 19 | sha256 = "022r3m9wdxljpbya69y2i3h9g3dhhfaqzidf95m6qjzms792jvgp"; 20 | type = "gem"; 21 | }; 22 | version = "2.8.0"; 23 | }; 24 | coffee-script = { 25 | dependencies = ["coffee-script-source" "execjs"]; 26 | groups = ["default" "jekyll_plugins"]; 27 | platforms = []; 28 | source = { 29 | remotes = ["https://rubygems.org"]; 30 | sha256 = "0rc7scyk7mnpfxqv5yy4y5q1hx3i7q3ahplcp4bq2g5r24g2izl2"; 31 | type = "gem"; 32 | }; 33 | version = "2.4.1"; 34 | }; 35 | coffee-script-source = { 36 | groups = ["default" "jekyll_plugins"]; 37 | platforms = []; 38 | source = { 39 | remotes = ["https://rubygems.org"]; 40 | sha256 = "0xfshhlz808f8639wc88wgls1mww35sid8rd55vn0a4yqajf4vh9"; 41 | type = "gem"; 42 | }; 43 | version = "1.11.1"; 44 | }; 45 | colorator = { 46 | groups = ["default" "jekyll_plugins"]; 47 | platforms = []; 48 | source = { 49 | remotes = ["https://rubygems.org"]; 50 | sha256 = "0f7wvpam948cglrciyqd798gdc6z3cfijciavd0dfixgaypmvy72"; 51 | type = "gem"; 52 | }; 53 | version = "1.1.0"; 54 | }; 55 | commonmarker = { 56 | dependencies = ["ruby-enum"]; 57 | groups = ["default" "jekyll_plugins"]; 58 | platforms = []; 59 | source = { 60 | remotes = ["https://rubygems.org"]; 61 | sha256 = "1pmjm87p0hxnknp33cxyvkgbr1swfp9gcznssmalm9z8kwyancb9"; 62 | type = "gem"; 63 | }; 64 | version = "0.17.13"; 65 | }; 66 | concurrent-ruby = { 67 | groups = ["default" "jekyll_plugins"]; 68 | platforms = []; 69 | source = { 70 | remotes = ["https://rubygems.org"]; 71 | sha256 = "0nwad3211p7yv9sda31jmbyw6sdafzmdi2i2niaz6f0wk5nq9h0f"; 72 | type = "gem"; 73 | }; 74 | version = "1.1.9"; 75 | }; 76 | dnsruby = { 77 | dependencies = ["simpleidn"]; 78 | groups = ["default" "jekyll_plugins"]; 79 | platforms = []; 80 | source = { 81 | remotes = ["https://rubygems.org"]; 82 | sha256 = "1pbhj4xmj4262in6c1nwl5ssw0qypg8ysjrrkwn2akkzbxzy9rfq"; 83 | type = "gem"; 84 | }; 85 | version = "1.61.7"; 86 | }; 87 | em-websocket = { 88 | dependencies = ["eventmachine" "http_parser.rb"]; 89 | groups = ["default" "jekyll_plugins"]; 90 | platforms = []; 91 | source = { 92 | remotes = ["https://rubygems.org"]; 93 | sha256 = "1mg1mx735a0k1l8y14ps2mxdwhi5r01ikydf34b0sp60v66nvbkb"; 94 | type = "gem"; 95 | }; 96 | version = "0.5.2"; 97 | }; 98 | ethon = { 99 | dependencies = ["ffi"]; 100 | groups = ["default" "jekyll_plugins"]; 101 | platforms = []; 102 | source = { 103 | remotes = ["https://rubygems.org"]; 104 | sha256 = "1bby4hbq96vnzcdbbybcbddin8dxdnj1ns758kcr4akykningqhh"; 105 | type = "gem"; 106 | }; 107 | version = "0.14.0"; 108 | }; 109 | eventmachine = { 110 | groups = ["default" "jekyll_plugins"]; 111 | platforms = []; 112 | source = { 113 | remotes = ["https://rubygems.org"]; 114 | sha256 = "0wh9aqb0skz80fhfn66lbpr4f86ya2z5rx6gm5xlfhd05bj1ch4r"; 115 | type = "gem"; 116 | }; 117 | version = "1.2.7"; 118 | }; 119 | execjs = { 120 | groups = ["default" "jekyll_plugins"]; 121 | platforms = []; 122 | source = { 123 | remotes = ["https://rubygems.org"]; 124 | sha256 = "121h6af4i6wr3wxvv84y53jcyw2sk71j5wsncm6wq6yqrwcrk4vd"; 125 | type = "gem"; 126 | }; 127 | version = "2.8.1"; 128 | }; 129 | faraday = { 130 | dependencies = ["faraday-em_http" "faraday-em_synchrony" "faraday-excon" "faraday-httpclient" "faraday-net_http" "faraday-net_http_persistent" "faraday-patron" "faraday-rack" "multipart-post" "ruby2_keywords"]; 131 | groups = ["default" "jekyll_plugins"]; 132 | platforms = []; 133 | source = { 134 | remotes = ["https://rubygems.org"]; 135 | sha256 = "0acqqv0w8nln89gf31ym8jsy12p70kc4fp40rrbsgs87vxvilia7"; 136 | type = "gem"; 137 | }; 138 | version = "1.7.1"; 139 | }; 140 | faraday-em_http = { 141 | groups = ["default" "jekyll_plugins"]; 142 | platforms = []; 143 | source = { 144 | remotes = ["https://rubygems.org"]; 145 | sha256 = "12cnqpbak4vhikrh2cdn94assh3yxza8rq2p9w2j34bqg5q4qgbs"; 146 | type = "gem"; 147 | }; 148 | version = "1.0.0"; 149 | }; 150 | faraday-em_synchrony = { 151 | groups = ["default" "jekyll_plugins"]; 152 | platforms = []; 153 | source = { 154 | remotes = ["https://rubygems.org"]; 155 | sha256 = "1vgrbhkp83sngv6k4mii9f2s9v5lmp693hylfxp2ssfc60fas3a6"; 156 | type = "gem"; 157 | }; 158 | version = "1.0.0"; 159 | }; 160 | faraday-excon = { 161 | groups = ["default" "jekyll_plugins"]; 162 | platforms = []; 163 | source = { 164 | remotes = ["https://rubygems.org"]; 165 | sha256 = "0h09wkb0k0bhm6dqsd47ac601qiaah8qdzjh8gvxfd376x1chmdh"; 166 | type = "gem"; 167 | }; 168 | version = "1.1.0"; 169 | }; 170 | faraday-httpclient = { 171 | groups = ["default" "jekyll_plugins"]; 172 | platforms = []; 173 | source = { 174 | remotes = ["https://rubygems.org"]; 175 | sha256 = "0fyk0jd3ks7fdn8nv3spnwjpzx2lmxmg2gh4inz3by1zjzqg33sc"; 176 | type = "gem"; 177 | }; 178 | version = "1.0.1"; 179 | }; 180 | faraday-net_http = { 181 | groups = ["default" "jekyll_plugins"]; 182 | platforms = []; 183 | source = { 184 | remotes = ["https://rubygems.org"]; 185 | sha256 = "1fi8sda5hc54v1w3mqfl5yz09nhx35kglyx72w7b8xxvdr0cwi9j"; 186 | type = "gem"; 187 | }; 188 | version = "1.0.1"; 189 | }; 190 | faraday-net_http_persistent = { 191 | groups = ["default" "jekyll_plugins"]; 192 | platforms = []; 193 | source = { 194 | remotes = ["https://rubygems.org"]; 195 | sha256 = "0dc36ih95qw3rlccffcb0vgxjhmipsvxhn6cw71l7ffs0f7vq30b"; 196 | type = "gem"; 197 | }; 198 | version = "1.2.0"; 199 | }; 200 | faraday-patron = { 201 | groups = ["default" "jekyll_plugins"]; 202 | platforms = []; 203 | source = { 204 | remotes = ["https://rubygems.org"]; 205 | sha256 = "19wgsgfq0xkski1g7m96snv39la3zxz6x7nbdgiwhg5v82rxfb6w"; 206 | type = "gem"; 207 | }; 208 | version = "1.0.0"; 209 | }; 210 | faraday-rack = { 211 | groups = ["default" "jekyll_plugins"]; 212 | platforms = []; 213 | source = { 214 | remotes = ["https://rubygems.org"]; 215 | sha256 = "1h184g4vqql5jv9s9im6igy00jp6mrah2h14py6mpf9bkabfqq7g"; 216 | type = "gem"; 217 | }; 218 | version = "1.0.0"; 219 | }; 220 | ffi = { 221 | groups = ["default" "jekyll_plugins"]; 222 | platforms = []; 223 | source = { 224 | remotes = ["https://rubygems.org"]; 225 | sha256 = "1wgvaclp4h9y8zkrgz8p2hqkrgr4j7kz0366mik0970w532cbmcq"; 226 | type = "gem"; 227 | }; 228 | version = "1.15.3"; 229 | }; 230 | forwardable-extended = { 231 | groups = ["default" "jekyll_plugins"]; 232 | platforms = []; 233 | source = { 234 | remotes = ["https://rubygems.org"]; 235 | sha256 = "15zcqfxfvsnprwm8agia85x64vjzr2w0xn9vxfnxzgcv8s699v0v"; 236 | type = "gem"; 237 | }; 238 | version = "2.6.0"; 239 | }; 240 | gemoji = { 241 | groups = ["default" "jekyll_plugins"]; 242 | platforms = []; 243 | source = { 244 | remotes = ["https://rubygems.org"]; 245 | sha256 = "0vgklpmhdz98xayln5hhqv4ffdyrglzwdixkn5gsk9rj94pkymc0"; 246 | type = "gem"; 247 | }; 248 | version = "3.0.1"; 249 | }; 250 | github-pages = { 251 | dependencies = ["github-pages-health-check" "jekyll" "jekyll-avatar" "jekyll-coffeescript" "jekyll-commonmark-ghpages" "jekyll-default-layout" "jekyll-feed" "jekyll-gist" "jekyll-github-metadata" "jekyll-mentions" "jekyll-optional-front-matter" "jekyll-paginate" "jekyll-readme-index" "jekyll-redirect-from" "jekyll-relative-links" "jekyll-remote-theme" "jekyll-sass-converter" "jekyll-seo-tag" "jekyll-sitemap" "jekyll-swiss" "jekyll-theme-architect" "jekyll-theme-cayman" "jekyll-theme-dinky" "jekyll-theme-hacker" "jekyll-theme-leap-day" "jekyll-theme-merlot" "jekyll-theme-midnight" "jekyll-theme-minimal" "jekyll-theme-modernist" "jekyll-theme-primer" "jekyll-theme-slate" "jekyll-theme-tactile" "jekyll-theme-time-machine" "jekyll-titles-from-headings" "jemoji" "kramdown" "kramdown-parser-gfm" "liquid" "mercenary" "minima" "nokogiri" "rouge" "terminal-table"]; 252 | groups = ["jekyll_plugins"]; 253 | platforms = []; 254 | source = { 255 | remotes = ["https://rubygems.org"]; 256 | sha256 = "1fh656rj9zh0j2k2sip8vyzk5dz6kg73ssxkkl9k93qglva4jwpy"; 257 | type = "gem"; 258 | }; 259 | version = "219"; 260 | }; 261 | github-pages-health-check = { 262 | dependencies = ["addressable" "dnsruby" "octokit" "public_suffix" "typhoeus"]; 263 | groups = ["default" "jekyll_plugins"]; 264 | platforms = []; 265 | source = { 266 | remotes = ["https://rubygems.org"]; 267 | sha256 = "1i77ljpjqcmr615ymckj30q3wa1rdv6ssbgsx8bjzqrwd1j1rlyf"; 268 | type = "gem"; 269 | }; 270 | version = "1.17.7"; 271 | }; 272 | html-pipeline = { 273 | dependencies = ["activesupport" "nokogiri"]; 274 | groups = ["default" "jekyll_plugins"]; 275 | platforms = []; 276 | source = { 277 | remotes = ["https://rubygems.org"]; 278 | sha256 = "080sn9z1a64gv04p318jz10y6lv6qd3avip08rrcmq9k4ihai0f1"; 279 | type = "gem"; 280 | }; 281 | version = "2.14.0"; 282 | }; 283 | "http_parser.rb" = { 284 | groups = ["default" "jekyll_plugins"]; 285 | platforms = []; 286 | source = { 287 | remotes = ["https://rubygems.org"]; 288 | sha256 = "15nidriy0v5yqfjsgsra51wmknxci2n2grliz78sf9pga3n0l7gi"; 289 | type = "gem"; 290 | }; 291 | version = "0.6.0"; 292 | }; 293 | i18n = { 294 | dependencies = ["concurrent-ruby"]; 295 | groups = ["default" "jekyll_plugins"]; 296 | platforms = []; 297 | source = { 298 | remotes = ["https://rubygems.org"]; 299 | sha256 = "038qvz7kd3cfxk8bvagqhakx68pfbnmghpdkx7573wbf0maqp9a3"; 300 | type = "gem"; 301 | }; 302 | version = "0.9.5"; 303 | }; 304 | jekyll = { 305 | dependencies = ["addressable" "colorator" "em-websocket" "i18n" "jekyll-sass-converter" "jekyll-watch" "kramdown" "liquid" "mercenary" "pathutil" "rouge" "safe_yaml"]; 306 | groups = ["default" "jekyll_plugins"]; 307 | platforms = []; 308 | source = { 309 | remotes = ["https://rubygems.org"]; 310 | sha256 = "0ci1v1mpad36191vzbm1050dxccwv6ky4yhdyvskmqxa6cf6v21j"; 311 | type = "gem"; 312 | }; 313 | version = "3.9.0"; 314 | }; 315 | jekyll-avatar = { 316 | dependencies = ["jekyll"]; 317 | groups = ["default" "jekyll_plugins"]; 318 | platforms = []; 319 | source = { 320 | remotes = ["https://rubygems.org"]; 321 | sha256 = "03bys2pl60vq92skfhlfqr2j68zhfjc86jffpg32f94wzjk8n0wk"; 322 | type = "gem"; 323 | }; 324 | version = "0.7.0"; 325 | }; 326 | jekyll-coffeescript = { 327 | dependencies = ["coffee-script" "coffee-script-source"]; 328 | groups = ["default" "jekyll_plugins"]; 329 | platforms = []; 330 | source = { 331 | remotes = ["https://rubygems.org"]; 332 | sha256 = "06qf4j9f6ysjb4bq6gsdaiz2ksmhc5yb484v458ra3s6ybccqvvy"; 333 | type = "gem"; 334 | }; 335 | version = "1.1.1"; 336 | }; 337 | jekyll-commonmark = { 338 | dependencies = ["commonmarker" "jekyll"]; 339 | groups = ["default" "jekyll_plugins"]; 340 | platforms = []; 341 | source = { 342 | remotes = ["https://rubygems.org"]; 343 | sha256 = "15kr36k56l4fh8yp7qswn9m91v7sa5kr2vq9w40li16z4n4akk57"; 344 | type = "gem"; 345 | }; 346 | version = "1.3.1"; 347 | }; 348 | jekyll-commonmark-ghpages = { 349 | dependencies = ["commonmarker" "jekyll-commonmark" "rouge"]; 350 | groups = ["default" "jekyll_plugins"]; 351 | platforms = []; 352 | source = { 353 | remotes = ["https://rubygems.org"]; 354 | sha256 = "1bhpk7iiz2p0hha650zxqq7rlbfj92m9qxxxasarrswszl4pcvp7"; 355 | type = "gem"; 356 | }; 357 | version = "0.1.6"; 358 | }; 359 | jekyll-default-layout = { 360 | dependencies = ["jekyll"]; 361 | groups = ["default" "jekyll_plugins"]; 362 | platforms = []; 363 | source = { 364 | remotes = ["https://rubygems.org"]; 365 | sha256 = "009zpd0mkmhkfp3s8yvh5mriqhil0ihv3gi2vw63flr3jz48y4kx"; 366 | type = "gem"; 367 | }; 368 | version = "0.1.4"; 369 | }; 370 | jekyll-feed = { 371 | dependencies = ["jekyll"]; 372 | groups = ["default" "jekyll_plugins"]; 373 | platforms = []; 374 | source = { 375 | remotes = ["https://rubygems.org"]; 376 | sha256 = "1zxqkrnix0xiw98531h5ga6h69jhzlx2jh9qhvcl67p8nq3sgza9"; 377 | type = "gem"; 378 | }; 379 | version = "0.15.1"; 380 | }; 381 | jekyll-gist = { 382 | dependencies = ["octokit"]; 383 | groups = ["default" "jekyll_plugins"]; 384 | platforms = []; 385 | source = { 386 | remotes = ["https://rubygems.org"]; 387 | sha256 = "03wz9j6yq3552nzf4g71qrdm9pfdgbm68abml9sjjgiaan1n8ns9"; 388 | type = "gem"; 389 | }; 390 | version = "1.5.0"; 391 | }; 392 | jekyll-github-metadata = { 393 | dependencies = ["jekyll" "octokit"]; 394 | groups = ["default" "jekyll_plugins"]; 395 | platforms = []; 396 | source = { 397 | remotes = ["https://rubygems.org"]; 398 | sha256 = "0r4m7r4qyd3pqkp5xlyp3zzy47i18kjgwq995nrspysgkmc4qmw1"; 399 | type = "gem"; 400 | }; 401 | version = "2.13.0"; 402 | }; 403 | jekyll-mentions = { 404 | dependencies = ["html-pipeline" "jekyll"]; 405 | groups = ["default" "jekyll_plugins"]; 406 | platforms = []; 407 | source = { 408 | remotes = ["https://rubygems.org"]; 409 | sha256 = "1n8y67plydfmay3jn865igvgb3h6s2crk8kq7ydk3wmn9h103s1r"; 410 | type = "gem"; 411 | }; 412 | version = "1.6.0"; 413 | }; 414 | jekyll-optional-front-matter = { 415 | dependencies = ["jekyll"]; 416 | groups = ["default" "jekyll_plugins"]; 417 | platforms = []; 418 | source = { 419 | remotes = ["https://rubygems.org"]; 420 | sha256 = "06vnxcmgkxm5nvrpv89qq0afjlxmadv63nh4ryglcwhlf4fhdp7c"; 421 | type = "gem"; 422 | }; 423 | version = "0.3.2"; 424 | }; 425 | jekyll-paginate = { 426 | groups = ["default" "jekyll_plugins"]; 427 | platforms = []; 428 | source = { 429 | remotes = ["https://rubygems.org"]; 430 | sha256 = "0r7bcs8fq98zldih4787zk5i9w24nz5wa26m84ssja95n3sas2l8"; 431 | type = "gem"; 432 | }; 433 | version = "1.1.0"; 434 | }; 435 | jekyll-readme-index = { 436 | dependencies = ["jekyll"]; 437 | groups = ["default" "jekyll_plugins"]; 438 | platforms = []; 439 | source = { 440 | remotes = ["https://rubygems.org"]; 441 | sha256 = "0chybr1zgnrmc7zf6psszcqnlrcy2jar8h77kci51lxj8vgc8k6p"; 442 | type = "gem"; 443 | }; 444 | version = "0.3.0"; 445 | }; 446 | jekyll-redirect-from = { 447 | dependencies = ["jekyll"]; 448 | groups = ["default" "jekyll_plugins"]; 449 | platforms = []; 450 | source = { 451 | remotes = ["https://rubygems.org"]; 452 | sha256 = "1nz6kd6qsa160lmjmls4zgx7fwcpp8ac07mpzy80z6zgd7jwldb6"; 453 | type = "gem"; 454 | }; 455 | version = "0.16.0"; 456 | }; 457 | jekyll-relative-links = { 458 | dependencies = ["jekyll"]; 459 | groups = ["default" "jekyll_plugins"]; 460 | platforms = []; 461 | source = { 462 | remotes = ["https://rubygems.org"]; 463 | sha256 = "0vfx90ajxyj24lz406k3pqknlbzy8nqs7wpz0in4ps9rggsh24yi"; 464 | type = "gem"; 465 | }; 466 | version = "0.6.1"; 467 | }; 468 | jekyll-remote-theme = { 469 | dependencies = ["addressable" "jekyll" "jekyll-sass-converter" "rubyzip"]; 470 | groups = ["default" "jekyll_plugins"]; 471 | platforms = []; 472 | source = { 473 | remotes = ["https://rubygems.org"]; 474 | sha256 = "0h2bwl42dig0282366kpxazxb8xafnppnd4yvq2dzcsg90kfgzfk"; 475 | type = "gem"; 476 | }; 477 | version = "0.4.3"; 478 | }; 479 | jekyll-sass-converter = { 480 | dependencies = ["sass"]; 481 | groups = ["default" "jekyll_plugins"]; 482 | platforms = []; 483 | source = { 484 | remotes = ["https://rubygems.org"]; 485 | sha256 = "008ikh5fk0n6ri54mylcl8jn0mq8p2nfyfqif2q3pp0lwilkcxsk"; 486 | type = "gem"; 487 | }; 488 | version = "1.5.2"; 489 | }; 490 | jekyll-seo-tag = { 491 | dependencies = ["jekyll"]; 492 | groups = ["default" "jekyll_plugins"]; 493 | platforms = []; 494 | source = { 495 | remotes = ["https://rubygems.org"]; 496 | sha256 = "0fsi75hymk2wswy216fs224p5ycrzjw1kshw1bsl5czhv42wr2w3"; 497 | type = "gem"; 498 | }; 499 | version = "2.7.1"; 500 | }; 501 | jekyll-sitemap = { 502 | dependencies = ["jekyll"]; 503 | groups = ["default" "jekyll_plugins"]; 504 | platforms = []; 505 | source = { 506 | remotes = ["https://rubygems.org"]; 507 | sha256 = "0622rwsn5i0m5xcyzdn86l68wgydqwji03lqixdfm1f1xdfqrq0d"; 508 | type = "gem"; 509 | }; 510 | version = "1.4.0"; 511 | }; 512 | jekyll-swiss = { 513 | groups = ["default" "jekyll_plugins"]; 514 | platforms = []; 515 | source = { 516 | remotes = ["https://rubygems.org"]; 517 | sha256 = "18w893f2snpbvgl80jnmq3xxsl5yi5a5qm11iy3gx0d8viasi6f2"; 518 | type = "gem"; 519 | }; 520 | version = "1.0.0"; 521 | }; 522 | jekyll-theme-architect = { 523 | dependencies = ["jekyll" "jekyll-seo-tag"]; 524 | groups = ["default" "jekyll_plugins"]; 525 | platforms = []; 526 | source = { 527 | remotes = ["https://rubygems.org"]; 528 | sha256 = "0h04zxlcdsb73qxh08xmsc36gmj95plwxr9g5zwzqd3bmbfd6xbj"; 529 | type = "gem"; 530 | }; 531 | version = "0.2.0"; 532 | }; 533 | jekyll-theme-cayman = { 534 | dependencies = ["jekyll" "jekyll-seo-tag"]; 535 | groups = ["default" "jekyll_plugins"]; 536 | platforms = []; 537 | source = { 538 | remotes = ["https://rubygems.org"]; 539 | sha256 = "0ajzhqhnj8gc5ns7i69kh69mzidvxkjs7yblrhzb13iaqzwi8prw"; 540 | type = "gem"; 541 | }; 542 | version = "0.2.0"; 543 | }; 544 | jekyll-theme-dinky = { 545 | dependencies = ["jekyll" "jekyll-seo-tag"]; 546 | groups = ["default" "jekyll_plugins"]; 547 | platforms = []; 548 | source = { 549 | remotes = ["https://rubygems.org"]; 550 | sha256 = "0z1clccf4q0g2zzhl1hfy3x2rcdjs6bzs9ab76lkmpphj5q2a2vj"; 551 | type = "gem"; 552 | }; 553 | version = "0.2.0"; 554 | }; 555 | jekyll-theme-hacker = { 556 | dependencies = ["jekyll" "jekyll-seo-tag"]; 557 | groups = ["default" "jekyll_plugins"]; 558 | platforms = []; 559 | source = { 560 | remotes = ["https://rubygems.org"]; 561 | sha256 = "12ppp0bxffy838p4my79nppq112fazifr3cxwvhv3l6yjbwzjsw1"; 562 | type = "gem"; 563 | }; 564 | version = "0.2.0"; 565 | }; 566 | jekyll-theme-leap-day = { 567 | dependencies = ["jekyll" "jekyll-seo-tag"]; 568 | groups = ["default" "jekyll_plugins"]; 569 | platforms = []; 570 | source = { 571 | remotes = ["https://rubygems.org"]; 572 | sha256 = "1lf7bbpr2s2rir2nf07rnh2g9mjy6zidpacs3j45la70b8qah7lj"; 573 | type = "gem"; 574 | }; 575 | version = "0.2.0"; 576 | }; 577 | jekyll-theme-merlot = { 578 | dependencies = ["jekyll" "jekyll-seo-tag"]; 579 | groups = ["default" "jekyll_plugins"]; 580 | platforms = []; 581 | source = { 582 | remotes = ["https://rubygems.org"]; 583 | sha256 = "0ifmvq44vwmkp6sb79ys8lx5w24gn3dhdr32bg562da2c8dv5wnb"; 584 | type = "gem"; 585 | }; 586 | version = "0.2.0"; 587 | }; 588 | jekyll-theme-midnight = { 589 | dependencies = ["jekyll" "jekyll-seo-tag"]; 590 | groups = ["default" "jekyll_plugins"]; 591 | platforms = []; 592 | source = { 593 | remotes = ["https://rubygems.org"]; 594 | sha256 = "1plindxr5vrk98frzxbnkashgnqs86xkg26rjmhgz0qf6mkz77q0"; 595 | type = "gem"; 596 | }; 597 | version = "0.2.0"; 598 | }; 599 | jekyll-theme-minimal = { 600 | dependencies = ["jekyll" "jekyll-seo-tag"]; 601 | groups = ["default" "jekyll_plugins"]; 602 | platforms = []; 603 | source = { 604 | remotes = ["https://rubygems.org"]; 605 | sha256 = "10idwpbqjqfc5i895ijf74ac79lccxpz30bvwp4x4fjp6l6229d2"; 606 | type = "gem"; 607 | }; 608 | version = "0.2.0"; 609 | }; 610 | jekyll-theme-modernist = { 611 | dependencies = ["jekyll" "jekyll-seo-tag"]; 612 | groups = ["default" "jekyll_plugins"]; 613 | platforms = []; 614 | source = { 615 | remotes = ["https://rubygems.org"]; 616 | sha256 = "1kzvdnk1vw8y6x8gy340mhnxipxh9p1h1h20br68clyxbsy7brsb"; 617 | type = "gem"; 618 | }; 619 | version = "0.2.0"; 620 | }; 621 | jekyll-theme-primer = { 622 | dependencies = ["jekyll" "jekyll-github-metadata" "jekyll-seo-tag"]; 623 | groups = ["default" "jekyll_plugins"]; 624 | platforms = []; 625 | source = { 626 | remotes = ["https://rubygems.org"]; 627 | sha256 = "1cq7lfwa3xs8hkx3cmv2ics7cr4r2azv66m0gfav0zi1k0kjh9yf"; 628 | type = "gem"; 629 | }; 630 | version = "0.6.0"; 631 | }; 632 | jekyll-theme-slate = { 633 | dependencies = ["jekyll" "jekyll-seo-tag"]; 634 | groups = ["default" "jekyll_plugins"]; 635 | platforms = []; 636 | source = { 637 | remotes = ["https://rubygems.org"]; 638 | sha256 = "0f9l7kaafab2cphkx8gh4b12d8zzbg2ig7x2qzxvxfqjwyfr0h2y"; 639 | type = "gem"; 640 | }; 641 | version = "0.2.0"; 642 | }; 643 | jekyll-theme-tactile = { 644 | dependencies = ["jekyll" "jekyll-seo-tag"]; 645 | groups = ["default" "jekyll_plugins"]; 646 | platforms = []; 647 | source = { 648 | remotes = ["https://rubygems.org"]; 649 | sha256 = "0li64hnjp4qw7fwsdx0767z7mwxn3kri6sqlg9fkicnmmr41p1mp"; 650 | type = "gem"; 651 | }; 652 | version = "0.2.0"; 653 | }; 654 | jekyll-theme-time-machine = { 655 | dependencies = ["jekyll" "jekyll-seo-tag"]; 656 | groups = ["default" "jekyll_plugins"]; 657 | platforms = []; 658 | source = { 659 | remotes = ["https://rubygems.org"]; 660 | sha256 = "1qjgsw2n3zny345h540n6rm9600mad7rs33qf6k4rhngxjkr0d5w"; 661 | type = "gem"; 662 | }; 663 | version = "0.2.0"; 664 | }; 665 | jekyll-titles-from-headings = { 666 | dependencies = ["jekyll"]; 667 | groups = ["default" "jekyll_plugins"]; 668 | platforms = []; 669 | source = { 670 | remotes = ["https://rubygems.org"]; 671 | sha256 = "10c4sa3gwyidmkcs8h6223lmqpw3h09mn7w8hxfppsk1wda6fdkp"; 672 | type = "gem"; 673 | }; 674 | version = "0.5.3"; 675 | }; 676 | jekyll-watch = { 677 | dependencies = ["listen"]; 678 | groups = ["default" "jekyll_plugins"]; 679 | platforms = []; 680 | source = { 681 | remotes = ["https://rubygems.org"]; 682 | sha256 = "1qd7hy1kl87fl7l0frw5qbn22x7ayfzlv9a5ca1m59g0ym1ysi5w"; 683 | type = "gem"; 684 | }; 685 | version = "2.2.1"; 686 | }; 687 | jemoji = { 688 | dependencies = ["gemoji" "html-pipeline" "jekyll"]; 689 | groups = ["default" "jekyll_plugins"]; 690 | platforms = []; 691 | source = { 692 | remotes = ["https://rubygems.org"]; 693 | sha256 = "09sxbnrqz5vf6rxmh6lzism31gz2g3hw86ymg37r1ccknclv3cp9"; 694 | type = "gem"; 695 | }; 696 | version = "0.12.0"; 697 | }; 698 | kramdown = { 699 | dependencies = ["rexml"]; 700 | groups = ["default" "jekyll_plugins"]; 701 | platforms = []; 702 | source = { 703 | remotes = ["https://rubygems.org"]; 704 | sha256 = "0jdbcjv4v7sj888bv3vc6d1dg4ackkh7ywlmn9ln2g9alk7kisar"; 705 | type = "gem"; 706 | }; 707 | version = "2.3.1"; 708 | }; 709 | kramdown-parser-gfm = { 710 | dependencies = ["kramdown"]; 711 | groups = ["default" "jekyll_plugins"]; 712 | platforms = []; 713 | source = { 714 | remotes = ["https://rubygems.org"]; 715 | sha256 = "0a8pb3v951f4x7h968rqfsa19c8arz21zw1vaj42jza22rap8fgv"; 716 | type = "gem"; 717 | }; 718 | version = "1.1.0"; 719 | }; 720 | liquid = { 721 | groups = ["default" "jekyll_plugins"]; 722 | platforms = []; 723 | source = { 724 | remotes = ["https://rubygems.org"]; 725 | sha256 = "0zhg5ha8zy8zw9qr3fl4wgk4r5940n4128xm2pn4shpbzdbsj5by"; 726 | type = "gem"; 727 | }; 728 | version = "4.0.3"; 729 | }; 730 | listen = { 731 | dependencies = ["rb-fsevent" "rb-inotify"]; 732 | groups = ["default" "jekyll_plugins"]; 733 | platforms = []; 734 | source = { 735 | remotes = ["https://rubygems.org"]; 736 | sha256 = "0ncfhdkjiwq9l1pm87ax2pa20kz2j0dz56vi74cnr5a6cfk0qb5p"; 737 | type = "gem"; 738 | }; 739 | version = "3.7.0"; 740 | }; 741 | mercenary = { 742 | groups = ["default" "jekyll_plugins"]; 743 | platforms = []; 744 | source = { 745 | remotes = ["https://rubygems.org"]; 746 | sha256 = "10la0xw82dh5mqab8bl0dk21zld63cqxb1g16fk8cb39ylc4n21a"; 747 | type = "gem"; 748 | }; 749 | version = "0.3.6"; 750 | }; 751 | mini_portile2 = { 752 | groups = ["default" "jekyll_plugins"]; 753 | platforms = []; 754 | source = { 755 | remotes = ["https://rubygems.org"]; 756 | sha256 = "1lvxm91hi0pabnkkg47wh1siv56s6slm2mdq1idfm86dyfidfprq"; 757 | type = "gem"; 758 | }; 759 | version = "2.6.1"; 760 | }; 761 | minima = { 762 | dependencies = ["jekyll" "jekyll-feed" "jekyll-seo-tag"]; 763 | groups = ["default" "jekyll_plugins"]; 764 | platforms = []; 765 | source = { 766 | remotes = ["https://rubygems.org"]; 767 | sha256 = "1gk7jmriiswda1ykjzpsw9cpiya4m9n0yrh0h6xnrc8zcfy543jj"; 768 | type = "gem"; 769 | }; 770 | version = "2.5.1"; 771 | }; 772 | minitest = { 773 | groups = ["default" "jekyll_plugins"]; 774 | platforms = []; 775 | source = { 776 | remotes = ["https://rubygems.org"]; 777 | sha256 = "19z7wkhg59y8abginfrm2wzplz7py3va8fyngiigngqvsws6cwgl"; 778 | type = "gem"; 779 | }; 780 | version = "5.14.4"; 781 | }; 782 | multipart-post = { 783 | groups = ["default" "jekyll_plugins"]; 784 | platforms = []; 785 | source = { 786 | remotes = ["https://rubygems.org"]; 787 | sha256 = "1zgw9zlwh2a6i1yvhhc4a84ry1hv824d6g2iw2chs3k5aylpmpfj"; 788 | type = "gem"; 789 | }; 790 | version = "2.1.1"; 791 | }; 792 | nokogiri = { 793 | dependencies = ["mini_portile2" "racc"]; 794 | groups = ["default" "jekyll_plugins"]; 795 | platforms = []; 796 | source = { 797 | remotes = ["https://rubygems.org"]; 798 | sha256 = "1sad16idsxayhaaswc3bksii1ydiqyzikl7y0ng35cn7w4g1dv3z"; 799 | type = "gem"; 800 | }; 801 | version = "1.12.4"; 802 | }; 803 | octokit = { 804 | dependencies = ["faraday" "sawyer"]; 805 | groups = ["default" "jekyll_plugins"]; 806 | platforms = []; 807 | source = { 808 | remotes = ["https://rubygems.org"]; 809 | sha256 = "0ak64rb48d8z98nw6q70r6i0i3ivv61iqla40ss5l79491qfnn27"; 810 | type = "gem"; 811 | }; 812 | version = "4.21.0"; 813 | }; 814 | pathutil = { 815 | dependencies = ["forwardable-extended"]; 816 | groups = ["default" "jekyll_plugins"]; 817 | platforms = []; 818 | source = { 819 | remotes = ["https://rubygems.org"]; 820 | sha256 = "12fm93ljw9fbxmv2krki5k5wkvr7560qy8p4spvb9jiiaqv78fz4"; 821 | type = "gem"; 822 | }; 823 | version = "0.16.2"; 824 | }; 825 | public_suffix = { 826 | groups = ["default" "jekyll_plugins"]; 827 | platforms = []; 828 | source = { 829 | remotes = ["https://rubygems.org"]; 830 | sha256 = "1xqcgkl7bwws1qrlnmxgh8g4g9m10vg60bhlw40fplninb3ng6d9"; 831 | type = "gem"; 832 | }; 833 | version = "4.0.6"; 834 | }; 835 | racc = { 836 | groups = ["default" "jekyll_plugins"]; 837 | platforms = []; 838 | source = { 839 | remotes = ["https://rubygems.org"]; 840 | sha256 = "178k7r0xn689spviqzhvazzvxfq6fyjldxb3ywjbgipbfi4s8j1g"; 841 | type = "gem"; 842 | }; 843 | version = "1.5.2"; 844 | }; 845 | rb-fsevent = { 846 | groups = ["default" "jekyll_plugins"]; 847 | platforms = []; 848 | source = { 849 | remotes = ["https://rubygems.org"]; 850 | sha256 = "1qsx9c4jr11vr3a9s5j83avczx9qn9rjaf32gxpc2v451hvbc0is"; 851 | type = "gem"; 852 | }; 853 | version = "0.11.0"; 854 | }; 855 | rb-inotify = { 856 | dependencies = ["ffi"]; 857 | groups = ["default" "jekyll_plugins"]; 858 | platforms = []; 859 | source = { 860 | remotes = ["https://rubygems.org"]; 861 | sha256 = "1jm76h8f8hji38z3ggf4bzi8vps6p7sagxn3ab57qc0xyga64005"; 862 | type = "gem"; 863 | }; 864 | version = "0.10.1"; 865 | }; 866 | rexml = { 867 | groups = ["default" "jekyll_plugins"]; 868 | platforms = []; 869 | source = { 870 | remotes = ["https://rubygems.org"]; 871 | sha256 = "08ximcyfjy94pm1rhcx04ny1vx2sk0x4y185gzn86yfsbzwkng53"; 872 | type = "gem"; 873 | }; 874 | version = "3.2.5"; 875 | }; 876 | rouge = { 877 | groups = ["default" "jekyll_plugins"]; 878 | platforms = []; 879 | source = { 880 | remotes = ["https://rubygems.org"]; 881 | sha256 = "0b4b300i3m4m4kw7w1n9wgxwy16zccnb7271miksyzd0wq5b9pm3"; 882 | type = "gem"; 883 | }; 884 | version = "3.26.0"; 885 | }; 886 | ruby-enum = { 887 | dependencies = ["i18n"]; 888 | groups = ["default" "jekyll_plugins"]; 889 | platforms = []; 890 | source = { 891 | remotes = ["https://rubygems.org"]; 892 | sha256 = "1pys90hxylhyg969iw9lz3qai5lblf8xwbdg1g5aj52731a9k83p"; 893 | type = "gem"; 894 | }; 895 | version = "0.9.0"; 896 | }; 897 | ruby2_keywords = { 898 | groups = ["default" "jekyll_plugins"]; 899 | platforms = []; 900 | source = { 901 | remotes = ["https://rubygems.org"]; 902 | sha256 = "1vz322p8n39hz3b4a9gkmz9y7a5jaz41zrm2ywf31dvkqm03glgz"; 903 | type = "gem"; 904 | }; 905 | version = "0.0.5"; 906 | }; 907 | rubyzip = { 908 | groups = ["default" "jekyll_plugins"]; 909 | platforms = []; 910 | source = { 911 | remotes = ["https://rubygems.org"]; 912 | sha256 = "0grps9197qyxakbpw02pda59v45lfgbgiyw48i0mq9f2bn9y6mrz"; 913 | type = "gem"; 914 | }; 915 | version = "2.3.2"; 916 | }; 917 | safe_yaml = { 918 | groups = ["default" "jekyll_plugins"]; 919 | platforms = []; 920 | source = { 921 | remotes = ["https://rubygems.org"]; 922 | sha256 = "0j7qv63p0vqcd838i2iy2f76c3dgwzkiz1d1xkg7n0pbnxj2vb56"; 923 | type = "gem"; 924 | }; 925 | version = "1.0.5"; 926 | }; 927 | sass = { 928 | dependencies = ["sass-listen"]; 929 | groups = ["default" "jekyll_plugins"]; 930 | platforms = []; 931 | source = { 932 | remotes = ["https://rubygems.org"]; 933 | sha256 = "0p95lhs0jza5l7hqci1isflxakz83xkj97lkvxl919is0lwhv2w0"; 934 | type = "gem"; 935 | }; 936 | version = "3.7.4"; 937 | }; 938 | sass-listen = { 939 | dependencies = ["rb-fsevent" "rb-inotify"]; 940 | groups = ["default" "jekyll_plugins"]; 941 | platforms = []; 942 | source = { 943 | remotes = ["https://rubygems.org"]; 944 | sha256 = "0xw3q46cmahkgyldid5hwyiwacp590zj2vmswlll68ryvmvcp7df"; 945 | type = "gem"; 946 | }; 947 | version = "4.0.0"; 948 | }; 949 | sawyer = { 950 | dependencies = ["addressable" "faraday"]; 951 | groups = ["default" "jekyll_plugins"]; 952 | platforms = []; 953 | source = { 954 | remotes = ["https://rubygems.org"]; 955 | sha256 = "0yrdchs3psh583rjapkv33mljdivggqn99wkydkjdckcjn43j3cz"; 956 | type = "gem"; 957 | }; 958 | version = "0.8.2"; 959 | }; 960 | simpleidn = { 961 | dependencies = ["unf"]; 962 | groups = ["default" "jekyll_plugins"]; 963 | platforms = []; 964 | source = { 965 | remotes = ["https://rubygems.org"]; 966 | sha256 = "06f7w6ph3bzzqk212yylfp4jfx275shgp9zg3xszbpv1ny2skp9m"; 967 | type = "gem"; 968 | }; 969 | version = "0.2.1"; 970 | }; 971 | terminal-table = { 972 | dependencies = ["unicode-display_width"]; 973 | groups = ["default" "jekyll_plugins"]; 974 | platforms = []; 975 | source = { 976 | remotes = ["https://rubygems.org"]; 977 | sha256 = "1512cngw35hsmhvw4c05rscihc59mnj09m249sm9p3pik831ydqk"; 978 | type = "gem"; 979 | }; 980 | version = "1.8.0"; 981 | }; 982 | thread_safe = { 983 | groups = ["default" "jekyll_plugins"]; 984 | platforms = []; 985 | source = { 986 | remotes = ["https://rubygems.org"]; 987 | sha256 = "0nmhcgq6cgz44srylra07bmaw99f5271l0dpsvl5f75m44l0gmwy"; 988 | type = "gem"; 989 | }; 990 | version = "0.3.6"; 991 | }; 992 | typhoeus = { 993 | dependencies = ["ethon"]; 994 | groups = ["default" "jekyll_plugins"]; 995 | platforms = []; 996 | source = { 997 | remotes = ["https://rubygems.org"]; 998 | sha256 = "1m22yrkmbj81rzhlny81j427qdvz57yk5wbcf3km0nf3bl6qiygz"; 999 | type = "gem"; 1000 | }; 1001 | version = "1.4.0"; 1002 | }; 1003 | tzinfo = { 1004 | dependencies = ["thread_safe"]; 1005 | groups = ["default" "jekyll_plugins"]; 1006 | platforms = []; 1007 | source = { 1008 | remotes = ["https://rubygems.org"]; 1009 | sha256 = "0zwqqh6138s8b321fwvfbywxy00lw1azw4ql3zr0xh1aqxf8cnvj"; 1010 | type = "gem"; 1011 | }; 1012 | version = "1.2.9"; 1013 | }; 1014 | unf = { 1015 | dependencies = ["unf_ext"]; 1016 | groups = ["default" "jekyll_plugins"]; 1017 | platforms = []; 1018 | source = { 1019 | remotes = ["https://rubygems.org"]; 1020 | sha256 = "0bh2cf73i2ffh4fcpdn9ir4mhq8zi50ik0zqa1braahzadx536a9"; 1021 | type = "gem"; 1022 | }; 1023 | version = "0.1.4"; 1024 | }; 1025 | unf_ext = { 1026 | groups = ["default" "jekyll_plugins"]; 1027 | platforms = []; 1028 | source = { 1029 | remotes = ["https://rubygems.org"]; 1030 | sha256 = "0wc47r23h063l8ysws8sy24gzh74mks81cak3lkzlrw4qkqb3sg4"; 1031 | type = "gem"; 1032 | }; 1033 | version = "0.0.7.7"; 1034 | }; 1035 | unicode-display_width = { 1036 | groups = ["default" "jekyll_plugins"]; 1037 | platforms = []; 1038 | source = { 1039 | remotes = ["https://rubygems.org"]; 1040 | sha256 = "06i3id27s60141x6fdnjn5rar1cywdwy64ilc59cz937303q3mna"; 1041 | type = "gem"; 1042 | }; 1043 | version = "1.7.0"; 1044 | }; 1045 | zeitwerk = { 1046 | groups = ["default" "jekyll_plugins"]; 1047 | platforms = []; 1048 | source = { 1049 | remotes = ["https://rubygems.org"]; 1050 | sha256 = "1746czsjarixq0x05f7p3hpzi38ldg6wxnxxw74kbjzh1sdjgmpl"; 1051 | type = "gem"; 1052 | }; 1053 | version = "2.4.2"; 1054 | }; 1055 | } 1056 | -------------------------------------------------------------------------------- /test/org2jekyll-test.el: -------------------------------------------------------------------------------- 1 | ;;; org2jekyll-test.el --- Test org2jekyll 2 | ;;; Commentary: 3 | 4 | (require 'ert) 5 | (require 'el-mock) 6 | (require 'org2jekyll-utilities) 7 | 8 | ;;; Code: 9 | (ert-deftest test-org2jekyll-get-options-from-buffer () 10 | (let* ((blog-key "#+BLOG:") 11 | (blog-val "tony's blog") 12 | (date-key "#+DATE:") 13 | (date-val "some-date") 14 | (options-plist (with-temp-buffer (insert (concat blog-key " " blog-val "\n" 15 | date-key " " date-val "\n" 16 | "Beef fungus articles")) 17 | (org2jekyll-get-options-from-buffer)))) 18 | (should (string= blog-val (plist-get options-plist :blog))) 19 | (should (string= date-val (plist-get options-plist :date)))) 20 | (let* ((description-key "#+DESCRIPTION:") 21 | (description-val "") 22 | (categories-key "#+CATEGORIES:") 23 | (categories-val "some-category") 24 | (options-plist 25 | (with-temp-buffer 26 | (insert (concat description-key " " description-val "\n" 27 | categories-key " " categories-val "\n" 28 | "Beef fungus articles")) 29 | (org2jekyll-get-options-from-buffer)))) 30 | (should-not (plist-get options-plist :description)) 31 | (should (string= categories-val (plist-get options-plist :categories))))) 32 | 33 | (ert-deftest test-org2jekyll-get-options-from-file () 34 | (let* ((temp-file "/tmp/test-get-options-from-file") 35 | (blog-key "#+BLOG:") 36 | (blog-val "tony's blog") 37 | (date-key "#+DATE:") 38 | (date-val "some-date") 39 | (_ (with-temp-file temp-file (insert (concat blog-key " " blog-val "\n" 40 | date-key " " date-val "\n" 41 | "Beef fungus articles")))) 42 | (options-plist (org2jekyll-get-options-from-file temp-file)) 43 | (_ (delete-file temp-file))) 44 | (should (string= blog-val (plist-get options-plist :blog))) 45 | (should (string= date-val (plist-get options-plist :date))))) 46 | 47 | (ert-deftest test-org2jekyll-article-p () 48 | (let* ((temp-file "/tmp/test-org2jekyll-get-article-p") 49 | (layout-key "#+LAYOUT:") (layout-val "post") 50 | (date-key "#+DATE:") (date-val "some-date") 51 | (not-article-key "#+NOT-AN-ARTICLE:") (not-article-val "tony's blog") 52 | (_ (with-temp-file temp-file (insert (concat layout-key " " layout-val "\n" 53 | date-key " " date-val "\n")))) 54 | (article (org2jekyll-article-p temp-file)) 55 | (_ (delete-file temp-file)) 56 | (_ (with-temp-file temp-file (insert (concat not-article-key " " not-article-val "\n")))) 57 | (not-article (org2jekyll-article-p temp-file)) 58 | (_ (delete-file temp-file))) 59 | (should article) 60 | (should-not not-article))) 61 | 62 | (ert-deftest test-org2jekyll-make-slug () 63 | (should (string= "this-is-a-test" 64 | (org2jekyll--make-slug "this-is-a-test"))) 65 | (should (string= "forbidden-symbol" 66 | (org2jekyll--make-slug "forb~idd^en-symbol![](){}$#"))) 67 | (should (string= "你好-test" 68 | (org2jekyll--make-slug "你好-test"))) 69 | (should (string= "你好-большие-test" 70 | (org2jekyll--make-slug "你好-большие-test")))) 71 | 72 | (ert-deftest test-org2jekyll--draft-filename () 73 | (let ((org2jekyll-jekyll-post-ext ".ext")) 74 | (should (string= "/some/path/你好-test.ext" 75 | (org2jekyll--draft-filename "/some/path/" "你好-test"))) 76 | (should (string= "/some/path/你好-большие-test.ext" 77 | (org2jekyll--draft-filename "/some/path/" "你好-Большие-test"))) 78 | (should (string= "/some/path/forbidden-symbol.ext" 79 | (org2jekyll--draft-filename "/some/path/" "forbidden-symbol\\![](){}^$#"))))) 80 | 81 | (ert-deftest test-org2jekyll--space-separated-values-to-yaml () 82 | (should (string= "\n- jabber\n- emacs\n- gtalk\n- tools\n- authentication" 83 | (org2jekyll--space-separated-values-to-yaml "jabber emacs gtalk tools authentication"))) 84 | (should (string= "\n- jabber\n- emacs\n- gtalk\n- tools\n- authentication" 85 | (org2jekyll--space-separated-values-to-yaml "jabber emacs gtalk tools authentication"))) 86 | (should (string= "" 87 | (org2jekyll--space-separated-values-to-yaml nil))) 88 | (should (string= "" 89 | (org2jekyll--space-separated-values-to-yaml "")))) 90 | 91 | (ert-deftest test-org2jekyll--to-yaml-header () 92 | (should (string= "--- 93 | layout: post 94 | title: gtalk in emacs using jabber mode 95 | date: 2013-01-13 10:10 96 | author: Antoine R. Dumont 97 | categories: \n- jabber\n- emacs\n- tools\n- gtalk 98 | tags: \n- tag0\n- tag1\n- tag2 99 | excerpt: Installing jabber and using it from emacs + authentication tips and tricks 100 | comments: true 101 | permalink: /posts/gtalk/ 102 | --- 103 | " 104 | (org2jekyll--to-yaml-header '(("layout" . "post") 105 | ("title" . "gtalk in emacs using jabber mode") 106 | ("date" . "2013-01-13 10:10") 107 | ("author" . "Antoine R. Dumont") 108 | ("categories" . "\n- jabber\n- emacs\n- tools\n- gtalk") 109 | ("tags" . "\n- tag0\n- tag1\n- tag2") 110 | ("description" . "Installing jabber and using it from emacs + authentication tips and tricks") 111 | ("comments" . "true") 112 | ("permalink" . "/posts/gtalk/")))))) 113 | 114 | (ert-deftest test-org2jekyll--org-to-jekyll-metadata () 115 | (should (equal '(("layout" . "post") 116 | ("title" . "gtalk in emacs using jabber mode") 117 | ("date" . "2013-01-13") 118 | ("author" . "Antoine R. Dumont") 119 | ("categories" . " 120 | - jabber 121 | - emacs 122 | - tools 123 | - gtalk") 124 | ("excerpt" . "Installing jabber and using it from emacs + authentication tips and tricks") 125 | 126 | ("comments" . "true") 127 | ("permalink" . "/posts/gtalk/")) 128 | (org2jekyll--org-to-jekyll-metadata '(("layout" . "post") 129 | ("title" . "gtalk in emacs using jabber mode") 130 | ("date" . "2013-01-13") 131 | ("author" . "Antoine R. Dumont") 132 | ("categories" . "\n- jabber\n- emacs\n- tools\n- gtalk") 133 | ("description" . "Installing jabber and using it from emacs + authentication tips and tricks") 134 | ("comments" . "true") 135 | ("permalink" . "/posts/gtalk/")))))) 136 | 137 | (ert-deftest test-org2jekyll--compute-ready-jekyll-file-name () 138 | (should (string= "/home/user/org/2012-10-10-scratch.org" 139 | (let ((org2jekyll-source-directory "/home/user/org")) 140 | (org2jekyll--compute-ready-jekyll-file-name "2012-10-10" "/home/tony/org/scratch.org")))) 141 | (should (string= "/home/dude/repo/org/2020-05-10-awesome-post.org" 142 | (let ((org2jekyll-source-directory "/home/dude/repo/org")) 143 | (org2jekyll--compute-ready-jekyll-file-name "2020-05-10" "/home/dude/repo/org/some/nested/path/awesome-post.org")))) 144 | (should (string= "/some/path/folder/2009-12-01-scratch.org" 145 | (let* ((org2jekyll-source-directory "/some/path/folder") 146 | (fake-drafts-folder "fake-drafts-folder") 147 | (org2jekyll-jekyll-drafts-dir fake-drafts-folder)) 148 | (org2jekyll--compute-ready-jekyll-file-name "2009-12-01" (format "/some/path/folder/%s/scratch.org" fake-drafts-folder)))))) 149 | 150 | (ert-deftest test-org2jekyll--convert-timestamp-to-yyyy-dd-mm () 151 | "Convert to simple YYYY-MM-DD date like out of either org date of iso8601 like dates" 152 | (should (string= "2013-04-29" (org2jekyll--convert-timestamp-to-yyyy-dd-mm "2013-04-29 lun. 00:46"))) 153 | (should (string= "2013-04-29" (org2jekyll--convert-timestamp-to-yyyy-dd-mm "2013-04-29 00:46")))) 154 | 155 | (ert-deftest test-org2jekyll--convert-timestamp-to-yyyy-dd-mm-hh () 156 | "Convert org-mode date to iso8601 like date strings" 157 | (should (string= "2020-04-29 00:46" 158 | (org2jekyll--convert-timestamp-to-yyyy-dd-mm-hh "2020-04-29 lun. 00:46")))) 159 | 160 | (ert-deftest test-org2jekyll-remove-org-only-options () 161 | (let* ((test-options '(("startup" . "hidestars") 162 | ("options" . "toc:nil") 163 | ("author" . "me") 164 | ("date" . "2015-12-23 Sat 14:20") 165 | ("title" . "some-title"))) 166 | (expected-results '(("author" . "me") 167 | ("date" . "2015-12-23 Sat 14:20") 168 | ("title" . "some-title"))) 169 | (jekyll-options (org2jekyll-remove-org-only-options test-options))) 170 | (should (equal expected-results jekyll-options)))) 171 | 172 | (ert-deftest test-org2jekyll-read-metadata () 173 | (let* ((temp-file "/tmp/test-org2jekyll-read-metadata") 174 | (startup-key "#+STARTUP:") (startup-val "hidestars") 175 | (options-key "#+OPTIONS:") (options-val "H:2 num:nil tags:t toc:nil timestamps:t") 176 | (layout-key "#+LAYOUT:") (layout-val "default") 177 | (author-key "#+AUTHOR:") (author-val "me") 178 | (date-key "#+DATE:") (date-val "2015-12-23 Sat 14:20") 179 | (title-key "#+TITLE:") (title-val "some-title") 180 | (description-key "#+DESCRIPTION:") (description-val "desc") 181 | (tags-key "#+TAGS:") (tags-val "tag0 tag1") 182 | (categories-key "#+CATEGORIES:") (categories-val "cat0 cat1") 183 | (comments-key "#+COMMENTS:") (comments-val "true") 184 | (_ (with-temp-file temp-file 185 | (insert (concat startup-key " " startup-val "\n" 186 | options-key " " options-val "\n" 187 | layout-key " " layout-val "\n" 188 | title-key " " title-val "\n" 189 | date-key " " date-val "\n" 190 | categories-key " " categories-val "\n" 191 | tags-key " " tags-val "\n" 192 | author-key " " author-val "\n" 193 | description-key " " description-val "\n" 194 | comments-key " " comments-val "\n")))) 195 | (options-alist (org2jekyll-read-metadata temp-file)) 196 | (_ (delete-file temp-file))) 197 | (should (string= "default" (assoc-default "layout" options-alist))) 198 | (should (string= "some-title" (assoc-default "title" options-alist))) 199 | (should (string= "2015-12-23 14:20" (assoc-default "date" options-alist))) 200 | (should (string= "\n- cat0\n- cat1" (assoc-default "categories" options-alist))) 201 | (should (string= "\n- tag0\n- tag1" (assoc-default "tags" options-alist))) 202 | (should (string= "me" (assoc-default "author" options-alist))) 203 | (should (string= "desc" (assoc-default "description" options-alist))) 204 | (should (string= "true" (assoc-default "comments" options-alist))) 205 | (should (null (assoc-default "startup" options-alist))) 206 | (should (null (assoc-default "options" options-alist))))) 207 | 208 | (ert-deftest test-org2jekyll-read-metadata-required-headers () 209 | (let* ((temp-file "/tmp/test-org2jekyll-read-metadata-required-headers") 210 | (layout-key "#+LAYOUT:") (layout-val "post") 211 | (description-key "#+DESCRIPTION:") (description-val "desc") 212 | (_ (with-temp-file temp-file 213 | (insert (concat layout-key " " layout-val "\n" 214 | description-key " " description-val "\n")))) 215 | (options-alist (org2jekyll-read-metadata temp-file)) 216 | (_ (delete-file temp-file))) 217 | (should (string= "This org-mode file is missing required header(s): 218 | - The title is required, please add '#+TITLE' at the top of your org buffer. 219 | - The categories is required, please add '#+CATEGORIES' at the top of your org buffer. 220 | Publication skipped" options-alist)))) 221 | 222 | (ert-deftest test-org2jekyll-default-headers-template () 223 | (should (string= "#+STARTUP: showall 224 | #+STARTUP: hidestars 225 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 226 | #+LAYOUT: some-layout 227 | #+AUTHOR: blog-author 228 | #+DATE: post-date 229 | #+TITLE: post title with spaces 230 | #+DESCRIPTION: post some description 231 | #+TAGS: post-tag0 post-tag1 232 | #+CATEGORIES: post-category other-category" 233 | (org2jekyll-default-headers-template 234 | '(("startup" "showall") 235 | ("startup" "hidestars") 236 | ("options" "H:2 num:nil tags:t toc:nil timestamps:t") 237 | ("layout" "some-layout") 238 | ("author" "blog-author") 239 | ("date" "post-date") 240 | ("title" "post title with spaces") 241 | ("description" "post some description") 242 | ("tags" "post-tag0 post-tag1") 243 | ("categories" "post-category other-category")))))) 244 | 245 | (ert-deftest test-org2jekyll--optional-folder () 246 | (should (string= "hello/there" (org2jekyll--optional-folder "hello" "there"))) 247 | (should (string= "hello/" (org2jekyll--optional-folder "hello")))) 248 | 249 | (ert-deftest test-org2jekyll-input-directory () 250 | (let ((org2jekyll-source-directory "source-directory")) 251 | (should (string= "source-directory/there" (org2jekyll-input-directory "there"))) 252 | (should (string= "source-directory/" (org2jekyll-input-directory))))) 253 | 254 | (ert-deftest test-org2jekyll-output-directory () 255 | (let ((org2jekyll-jekyll-directory "out-directory")) 256 | (should (string= "out-directory/there" (org2jekyll-output-directory "there"))) 257 | (should (string= "out-directory/" (org2jekyll-output-directory))))) 258 | 259 | (ert-deftest test-org2jekyll-read-metadata-and-execute () 260 | (should (string= "Post 'some-org-file' published!" 261 | (mocklet (((org2jekyll-article-p "org-file") => t) 262 | ((file-name-nondirectory "org-file") => "some-org-file") 263 | ((org2jekyll-read-metadata "org-file") => '(("layout" . "post")))) 264 | (org2jekyll-read-metadata-and-execute (lambda (org-metadata org-file) 2) "org-file")))) 265 | (should (string= "'some-org-file' is not an article, publication skipped!" 266 | (mocklet (((org2jekyll-article-p "org-file") => nil) 267 | ((file-name-nondirectory "org-file") => "some-org-file")) 268 | (org2jekyll-read-metadata-and-execute (lambda (org-metadata org-file) 2) "org-file")))) 269 | (should (string= "org2jekyll - some message" 270 | (mocklet (((org2jekyll-article-p "org-file") => t) 271 | ((org2jekyll-read-metadata "org-file") => "some message")) 272 | (org2jekyll-read-metadata-and-execute (lambda (org-metadata org-file) 2) "org-file"))))) 273 | 274 | (ert-deftest test-org2jekyll-publish-temp-file-then-cleanup () 275 | "Temporary file should be published then cleaned-up" 276 | (should (eq :published-file 277 | (let ((temp-file "/tmp/temp-file")) 278 | (with-mock 279 | (mock (copy-file :org-file temp-file 'overwrite 'keep-time 'preserve-ids 'preserve-perms) => nil) 280 | (mock (org-publish-file temp-file :project-metadata)) 281 | (org2jekyll--publish-temp-file-then-cleanup :org-file "/tmp/temp-file" :project-metadata)) 282 | (if (file-exists-p temp-file) 283 | :something-is-wrong 284 | :published-file))))) 285 | 286 | (ert-deftest test-org2jekyll--publish-post-org-file-with-metadata () 287 | (should (eq :published-post-file 288 | (let ((org-publish-project-alist '((:post :project))) 289 | (temp-file "/tmp/temp-file")) 290 | (with-mock 291 | (mock (org2jekyll--convert-timestamp-to-yyyy-dd-mm :date) => :date) 292 | (mock (org2jekyll--compute-ready-jekyll-file-name :date :org-file) => temp-file) 293 | (mock (org2jekyll--publish-temp-file-then-cleanup :org-file temp-file 294 | '(:post :project)) => :published-post-file) 295 | (org2jekyll--publish-post-org-file-with-metadata '(("layout" . :post) 296 | ("date" . :date)) 297 | :org-file)))))) 298 | 299 | (ert-deftest test-org2jekyll--publish-page-org-file-with-metadata () 300 | (should (eq :published-page-file 301 | (let ((org-publish-project-alist '((:page :project))) 302 | (org2jekyll-source-directory "/tmp/") 303 | (temp-file "/tmp/filename.org2jekyll")) 304 | (with-mock 305 | (mock (org2jekyll--publish-temp-file-then-cleanup "filename.org" 306 | temp-file 307 | '(:page :project)) => :published-page-file) 308 | (org2jekyll--publish-page-org-file-with-metadata '(("layout" . :page) 309 | ("date" . :date)) "filename.org")))))) 310 | 311 | (ert-deftest test-org2jekyll-post-p () 312 | "With default layouts" 313 | (should (org2jekyll-post-p "post")) 314 | (should-not (org2jekyll-post-p "default"))) 315 | 316 | (ert-deftest test-org2jekyll-post-p-with-customs () 317 | "With customs layouts" 318 | (should 319 | (let ((org2jekyll-jekyll-layout-post "something")) 320 | (org2jekyll-post-p "something"))) 321 | (should-not 322 | (let ((org2jekyll-jekyll-layout-post "something")) 323 | (org2jekyll-post-p "default")))) 324 | 325 | (ert-deftest test-org2jekyll-page-p () 326 | "With default layouts" 327 | (should (org2jekyll-page-p "default")) 328 | (should-not (org2jekyll-page-p "post"))) 329 | 330 | (ert-deftest test-org2jekyll-page-p-with-customs () 331 | "With custom layouts" 332 | (should 333 | (let ((org2jekyll-jekyll-layout-page "post")) 334 | (org2jekyll-page-p "post"))) 335 | (should-not 336 | (let ((org2jekyll-jekyll-layout-page "else")) 337 | (org2jekyll-page-p "post")))) 338 | 339 | (ert-deftest test-org2jekyll-check-metadata () 340 | (let* ((temp-file "/tmp/test-org2jekyll-check-metadata") 341 | (startup-key "#+STARTUP:") (startup-val "hidestars") 342 | (options-key "#+OPTIONS:") (options-val "H:2 num:nil tags:t toc:nil timestamps:t") 343 | (layout-key "#+LAYOUT:") (layout-val "some-layout") 344 | (author-key "#+AUTHOR:") (author-val "blog-author") 345 | (date-key "#+DATE:") (date-val "post-date") 346 | (title-key "#+TITLE:") (title-val "post title with spaces") 347 | (description-key "#+DESCRIPTION:") (description-val "post some description") 348 | (tags-key "#+TAGS:") (tags-val "post-tag0 post-tag1") 349 | (categories-key "#+CATEGORIES:") (categories-val "post-category other-category") 350 | (_ (with-temp-file temp-file 351 | (insert (concat startup-key " " startup-val "\n" 352 | options-key " " options-val "\n" 353 | layout-key " " layout-val "\n" 354 | author-key " " author-val "\n" 355 | date-key " " date-val "\n" 356 | title-key " " title-val "\n" 357 | description-key " " description-val "\n" 358 | tags-key " " tags-val "\n" 359 | categories-key " " categories-val "\n")))) 360 | (options-plist (org2jekyll-get-options-from-file temp-file)) 361 | (_ (delete-file temp-file)) 362 | (metadata-errors (org2jekyll-check-metadata options-plist))) 363 | (should (null metadata-errors))) 364 | (should (string= "- The title is required, please add '#+TITLE' at the top of your org buffer. 365 | - The categories is required, please add '#+CATEGORIES' at the top of your org buffer. 366 | - The description is required, please add '#+DESCRIPTION' at the top of your org buffer. 367 | - The layout is required, please add '#+LAYOUT' at the top of your org buffer." 368 | (org2jekyll-check-metadata nil))) 369 | (should (string= "- The categories is required, please add '#+CATEGORIES' at the top of your org buffer. 370 | - The description is required, please add '#+DESCRIPTION' at the top of your org buffer." 371 | (org2jekyll-check-metadata '(:title "some-title" 372 | :layout "some-layout")))) 373 | (should-not (org2jekyll-check-metadata '(:title "some-title" 374 | :layout "some-layout" 375 | :author "some-author" 376 | :categories "some-categories" 377 | :description "some-description")))) 378 | 379 | (ert-deftest test-org2jekyll--yaml-escape () 380 | (should (string= "this is a title" 381 | (org2jekyll--yaml-escape "this is a title"))) 382 | (should (string= "\"title:\"" 383 | (org2jekyll--yaml-escape "title:"))) 384 | (should (string= "\"\\\"title:\\\"\"" 385 | (org2jekyll--yaml-escape "\"title:\"")))) 386 | 387 | (ert-deftest test-org2jekyll--list-dir () 388 | (should (equal :found 389 | (with-mock (mock (find-file "found-file") => :found) 390 | (org2jekyll--list-dir "found-file")))) 391 | (should-not (with-mock (mock (find-file "unknown") => nil) 392 | (org2jekyll--list-dir "unknown")))) 393 | 394 | (ert-deftest test-org2jekyll-list-posts () 395 | (should (equal :found 396 | (let ((org2jekyll-jekyll-directory "path-to-jekyll-root") 397 | (org2jekyll-jekyll-posts-dir "some-posts-dir")) 398 | (with-mock (mock (find-file "path-to-jekyll-root/some-posts-dir") => :found) 399 | (org2jekyll-list-posts)))))) 400 | 401 | (ert-deftest test-org2jekyll-list-drafts () 402 | (should (equal :found 403 | (let ((org2jekyll-source-directory "path-to-org-source-root") 404 | (org2jekyll-jekyll-drafts-dir "some-drafts-dir")) 405 | (with-mock (mock (find-file "path-to-org-source-root/some-drafts-dir") => :found) 406 | (org2jekyll-list-drafts)))))) 407 | 408 | (ert-deftest test-org2jekyll-message () 409 | (should (string= "org2jekyll - this is a message" 410 | (org2jekyll-message "this is a %s" "message"))) 411 | (should (string= "org2jekyll - this is another message!" 412 | (org2jekyll-message "this is %s %s!" "another" "message")))) 413 | 414 | (ert-deftest test-org2jekyll-now () 415 | (should (string= :date 416 | (with-mock (mock (format-time-string "%Y-%m-%d %a %H:%M") => :date) 417 | (org2jekyll-now))))) 418 | 419 | (ert-deftest test-org2jekyll-create-draft () 420 | (should (string= "#+STARTUP: showall 421 | #+STARTUP: hidestars 422 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 423 | #+LAYOUT: post 424 | #+AUTHOR: tony 425 | #+DATE: some date 426 | #+TITLE: some title 427 | #+DESCRIPTION: some description 428 | #+TAGS: tag0 tag1 429 | #+CATEGORIES: cat0 cat1 catn 430 | #+THEME: dark 431 | #+COMMENTS: false 432 | 433 | * " 434 | (progn 435 | ;; clean up 436 | (when (file-exists-p "/tmp/some-title.org") 437 | (delete-file "/tmp/some-title.org")) 438 | ;; Define extra headers 439 | (let ((org2jekyll-default-template-entries-extra 440 | '(("theme" "dark") 441 | ("comments" "false")))) 442 | ;; execute draft creation 443 | (save-excursion 444 | (let ((org2jekyll-source-directory "/tmp") 445 | (org2jekyll-jekyll-drafts-dir "") 446 | (org2jekyll-blog-author "tony")) 447 | (with-mock 448 | (mock (org2jekyll-now) => "some date") 449 | (mock (ido-completing-read "Layout: " '("post" "default") nil 'require-match) => "post") 450 | (mock (org2jekyll--read-title) => "some title") 451 | (mock (org2jekyll--read-description) => "some description") 452 | (mock (org2jekyll--read-tags) => "tag0 tag1") 453 | (mock (org2jekyll--read-categories) => "cat0 cat1 catn") 454 | (mock (org2jekyll-input-directory "") => "/tmp") 455 | (mock (org2jekyll--draft-filename * *) => "/tmp/some-title.org") 456 | (mock (find-file "/tmp/some-title.org") => nil) 457 | (call-interactively #'org2jekyll-create-draft))))) 458 | ;; read the created file 459 | (with-temp-buffer 460 | (insert-file-contents "/tmp/some-title.org") 461 | (buffer-substring-no-properties (point-min) (point-max))))))) 462 | 463 | (ert-deftest test-org2jekyll-init-current-buffer () 464 | (should (string= "#+STARTUP: showall 465 | #+STARTUP: hidestars 466 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 467 | #+LAYOUT: some-layout 468 | #+AUTHOR: dude 469 | #+DATE: some-date 470 | #+TITLE: some-title 471 | #+DESCRIPTION: some-desc 472 | #+TAGS: some-tags 473 | #+CATEGORIES: some-cat 474 | 475 | * some blog 476 | * already present 477 | " 478 | (org2jekyll-tests-with-temp-buffer-and-return-content 479 | "* some blog 480 | * already present 481 | " 482 | (with-mock 483 | (mock (org2jekyll--init-buffer-metadata *) => '(:author "dude" 484 | :date "some-date" 485 | :layout "some-layout" 486 | :title "some-title" 487 | :description "some-desc" 488 | :tags "some-tags" 489 | :categories "some-cat")) 490 | (call-interactively #'org2jekyll-init-current-buffer))))) 491 | (should (string= "#+TITLE: already-present-title 492 | #+STARTUP: showall 493 | #+STARTUP: hidestars 494 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 495 | #+LAYOUT: some-layout 496 | #+AUTHOR: dude 497 | #+DATE: some-date 498 | #+DESCRIPTION: some-desc 499 | #+TAGS: some-tags 500 | #+CATEGORIES: some-cat 501 | " 502 | (org2jekyll-tests-with-temp-buffer-and-return-content 503 | "#+TITLE: already-present-title" 504 | (with-mock 505 | (mock (org2jekyll--init-buffer-metadata *) => '(:author "dude" 506 | :date "some-date" 507 | :layout "some-layout" 508 | :description "some-desc" 509 | :tags "some-tags" 510 | :categories "some-cat")) 511 | (call-interactively #'org2jekyll-init-current-buffer)))))) 512 | 513 | 514 | (ert-deftest test-org2jekyll--read-title () 515 | (should (string= "some super title" 516 | (with-mock 517 | (mock (read-string "Title: ") => "some super title") 518 | (org2jekyll--read-title)))) 519 | (should-not (with-mock 520 | (mock (read-string "Title: ")) 521 | (org2jekyll--read-title)))) 522 | 523 | (ert-deftest test-org2jekyll--read-description () 524 | (should (string= "some super description" 525 | (with-mock 526 | (mock (read-string "Description: ") => "some super description") 527 | (org2jekyll--read-description)))) 528 | (should-not (with-mock 529 | (mock (read-string "Description: ")) 530 | (org2jekyll--read-description)))) 531 | 532 | (ert-deftest test-org2jekyll--read-tags () 533 | (should (string= "tag0 tag10" 534 | (with-mock 535 | (mock (read-string "Tags (space separated values): ") => "tag0 tag10") 536 | (org2jekyll--read-tags)))) 537 | (should-not (with-mock 538 | (mock (read-string "Tags (space separated values): ")) 539 | (org2jekyll--read-tags)))) 540 | 541 | (ert-deftest test-org2jekyll--read-categories () 542 | (should (string= "cat0 cat10" 543 | (with-mock 544 | (mock (read-string "Categories (space separated values): ") => "cat0 cat10") 545 | (org2jekyll--read-categories)))) 546 | (should-not (with-mock 547 | (mock (read-string "Categories (space separated values): ")) 548 | (org2jekyll--read-categories)))) 549 | 550 | (ert-deftest test-org2jekyll--input-read () 551 | (should (eq :input-done 552 | (with-mock 553 | (mock (ido-completing-read :prompt 554 | :collection 555 | nil 556 | 'require-match) => :input-done) 557 | (org2jekyll--input-read :prompt :collection))))) 558 | 559 | (ert-deftest test-org2jekyll--init-buffer-metadata () 560 | (should (equal '(:author "dude" 561 | :date :some-date 562 | :layout :some-layout 563 | :description :some-desc 564 | :tags :some-tags 565 | :categories :some-cat) 566 | (let ((org2jekyll-blog-author "dude")) 567 | (with-mock 568 | (mock (org2jekyll-now) => :some-date) 569 | (mock (org2jekyll--input-read "Layout: " '("post" "default")) => :some-layout) 570 | (mock (org2jekyll--read-description) => :some-desc) 571 | (mock (org2jekyll--read-tags) => :some-tags) 572 | (mock (org2jekyll--read-categories) => :some-cat) 573 | (org2jekyll--init-buffer-metadata '(:title "existing title"))))))) 574 | 575 | (ert-deftest test-org2jekyll--get-template-entries () 576 | (let ((org2jekyll-default-template-entries-extra 577 | '(("flavour" "lemon") 578 | ("result" "big"))) 579 | (decided-options 580 | '(("layout" . "post") 581 | ("title" . "gtalk in emacs using jabber mode") 582 | ("date" . "2013-01-13 10:10") 583 | ("author" . "Antoine R. Dumont") 584 | ("categories" . "\n- jabber\n- emacs\n- tools\n- gtalk") 585 | ("tags" . "\n- tag0\n- tag1\n- tag2") 586 | ("description" . "Installing jabber and using it from emacs + authentication tips and tricks")))) 587 | (should (equal 588 | '(("startup" "showall") 589 | ("startup" "hidestars") 590 | ("options" "H:2 num:nil tags:t toc:nil timestamps:t") 591 | ("layout" . "post") 592 | ("author" . "Antoine R. Dumont") 593 | ("date" . "2013-01-13 10:10") 594 | ("title" . "gtalk in emacs using jabber mode") 595 | ("description" . "Installing jabber and using it from emacs + authentication tips and tricks") 596 | ("tags" . "\n- tag0\n- tag1\n- tag2") 597 | ("categories" . "\n- jabber\n- emacs\n- tools\n- gtalk") 598 | ("flavour" "lemon") 599 | ("result" "big")) 600 | (org2jekyll--get-template-entries decided-options))))) 601 | 602 | (ert-deftest test-org2jekyll--get-filtered-entries () 603 | (should (equal 604 | '(("layout" . "post") 605 | ("author" . "Antoine R. Dumont") 606 | ("date" . "2013-01-13 10:10") 607 | ("title" . "gtalk in emacs using jabber mode")) 608 | (org2jekyll--get-filtered-entries 609 | '(("startup" "showall") 610 | ("startup" "hidestars") 611 | ("options" "H:2 num:nil tags:t toc:nil timestamps:t") 612 | ("layout" . "post") 613 | ("author" . "Antoine R. Dumont") 614 | ("date" . "2013-01-13 10:10") 615 | ("title" . "gtalk in emacs using jabber mode") 616 | ("description" . "Installing jabber and using it from emacs + authentication tips and tricks")) 617 | '("description" "startup" "options" "nothing"))))) 618 | 619 | (ert-deftest test-org2jekyll-publish-web-project () 620 | (should (eq 'publish-done 621 | (with-mock 622 | (mock (org-publish-project "web") => 'publish-done) 623 | (org2jekyll-publish-web-project))))) 624 | 625 | (ert-deftest test-org2jekyll-publish-post () 626 | (should (eq :publish-post-done 627 | (with-mock 628 | (mock (org2jekyll-read-metadata-and-execute 629 | 'org2jekyll--publish-post-org-file-with-metadata 630 | :org-file) => :publish-post-done) 631 | (org2jekyll-publish-post :org-file))))) 632 | 633 | (ert-deftest test-org2jekyll-publish-page () 634 | (should (eq :publish-page-done 635 | (with-mock 636 | (mock (org2jekyll-read-metadata-and-execute 637 | 'org2jekyll--publish-page-org-file-with-metadata 638 | :org-file) => :publish-page-done) 639 | (org2jekyll-publish-page :org-file))))) 640 | 641 | (ert-deftest test-org2jekyll--bug-report () 642 | (should (string= "Please: 643 | - Describe your problem with clarity and conciceness (cf. https://www.gnu.org/software/emacs/manual/html_node/emacs/Understanding-Bug-Reporting.html) 644 | - Explicit your installation choice (melpa, marmalade, el-get, tarball, git clone...). 645 | - A sample of your configuration. 646 | - Report the following message trace inside your issue. 647 | 648 | System information: 649 | - system-type: system-type 650 | - locale-coding-system: locale-coding-system 651 | - emacs-version: emacs-version 652 | - org version: org-version 653 | - org2jekyll version: org2jekyll-version 654 | - org2jekyll path: /path/to/org2jekyll" 655 | 656 | (let ((system-type "system-type") 657 | (locale-coding-system "locale-coding-system") 658 | (org2jekyll--version "org2jekyll-version")) 659 | (with-mock 660 | (mock (emacs-version) => "emacs-version") 661 | (mock (org-version) => "org-version") 662 | (mock (find-library-name "org2jekyll") => "/path/to/org2jekyll") 663 | (org2jekyll--bug-report)))))) 664 | 665 | (ert-deftest test-org2jekyll-bug-report () 666 | (should (equal :res 667 | (with-mock 668 | (mock (browse-url "https://github.com/ardumont/org2jekyll/issues/new") => :opened) 669 | (mock (org2jekyll--bug-report) => :message) 670 | (mock (message :message) => :res) 671 | (org2jekyll-bug-report 'browse)))) 672 | (should (equal :res 673 | (with-mock 674 | (mock (org2jekyll--bug-report) => :message2) 675 | (mock (message :message2) => :res) 676 | (org2jekyll-bug-report))))) 677 | 678 | (ert-deftest test-org2jekyll-version () 679 | (should (string= "version-org2jekyll" 680 | (let ((org2jekyll--version "version-org2jekyll")) 681 | (call-interactively 'org2jekyll-version))))) 682 | 683 | (ert-deftest test-org2jekyll--without-option-p-no-options-passed () 684 | (should (with-temp-buffer 685 | (insert "#+OPTIONS: H:2 num:nil toc:nil timestamps:t\n") 686 | (org2jekyll--without-option-p "toc"))) 687 | ;; mentioned to t, activated 688 | (should-not (with-temp-buffer 689 | (insert "#+OPTIONS: H:2 num:nil toc:t timestamps:t\n") 690 | (org2jekyll--without-option-p "toc"))) 691 | ;; local option not present, activated 692 | (should-not (with-temp-buffer 693 | (insert "#+OPTIONS: H:2 num:nil timestamps:t\n") 694 | (org2jekyll--without-option-p "toc"))) 695 | ;; no options at all then it's activated 696 | (should-not (with-temp-buffer 697 | (org2jekyll--without-option-p "toc")))) 698 | 699 | (ert-deftest test-org2jekyll--without-option-p-options-passed () 700 | ;; Option parsing should be detected appropriately 701 | (should (with-temp-buffer 702 | (insert "#+OPTIONS: H:2 num:nil timestamps:t\n") 703 | (org2jekyll--without-option-p "num" (org2jekyll-get-options-from-buffer)))) 704 | 705 | (should-not (with-temp-buffer 706 | (insert "#+OPTIONS: H:2 toc:t timestamps:t\n") 707 | (org2jekyll--without-option-p "num" (org2jekyll-get-options-from-buffer)))) 708 | 709 | (should-not (with-temp-buffer 710 | (insert "#+OPTIONS: H:2 num:t timestamps:t\n") 711 | (org2jekyll--without-option-p "num" (org2jekyll-get-options-from-buffer))))) 712 | 713 | (ert-deftest test-org2jekyll--with-tags-p () 714 | ;; tags option parsing should be detected appropriately 715 | (should-not (with-temp-buffer 716 | (insert "#+OPTIONS: H:2 num:nil tags:nil timestamps:t\n") 717 | (org2jekyll--with-tags-p (org2jekyll-get-options-from-buffer)))) 718 | 719 | (should (with-temp-buffer 720 | (insert "#+OPTIONS: H:2 num:nil timestamps:t\n") 721 | (org2jekyll--with-tags-p (org2jekyll-get-options-from-buffer)))) 722 | 723 | (should (with-temp-buffer 724 | (insert "#+OPTIONS: H:2 num:t tags:t timestamps:t\n") 725 | (org2jekyll--with-tags-p (org2jekyll-get-options-from-buffer))))) 726 | 727 | (ert-deftest test-org2jekyll--header-entry () 728 | (should (string= "#+STARTUP: indent" 729 | (org2jekyll--header-entry '("startup" "indent")))) 730 | (should (string= "#+AUTHOR: %s" 731 | (org2jekyll--header-entry '("author"))))) 732 | 733 | (ert-deftest test-org2jekyll--header-entry () 734 | (should (string= "#+STARTUP: showall 735 | #+STARTUP: noindent 736 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 737 | #+LAYOUT: %s 738 | #+AUTHOR: %s 739 | 740 | " 741 | (org2jekyll--inline-headers '(("startup" "showall") 742 | ("startup" "noindent") 743 | ("options" "H:2 num:nil tags:t toc:nil timestamps:t") 744 | ("layout") 745 | ("author")))))) 746 | 747 | (ert-deftest test-org2jekyll--symbol-to-string () 748 | ;; :symbol should be converted to string 749 | (should (string= "source" 750 | (org2jekyll--symbol-to-string :source))) 751 | ;; if the symbol is a string already, it's only the first character which is 752 | ;; removed 753 | (should (string= "source" 754 | (org2jekyll--symbol-to-string ":source"))) 755 | ;; careful for some other symbols 756 | (should (string= "il" 757 | (org2jekyll--symbol-to-string nil)))) 758 | 759 | (ert-deftest test-org2jekyll--plist-to-alist () 760 | ;; convert from plist to alist should be fine 761 | (should (equal 762 | '(("date" . "2015-09-06 12:59") 763 | ("author" . "ardumont") 764 | ("startup" . "hidestars") 765 | ("options" . "H:2 num:t tags:t toc:t timestamps:t") 766 | ("layout" . "post") 767 | ("title" . "org-trello debug tools") 768 | ("description" . "org-trello debugging tools") 769 | ("tags" . "\n- tools\n- org-trello\n- debug") 770 | ("categories" . "\n- tools\n- org-trello\n- debug") 771 | ("permalink" . "/debug/")) 772 | (org2jekyll--plist-to-alist '(:date "2015-09-06 12:59" 773 | :author "ardumont" 774 | :startup "hidestars" 775 | :options "H:2 num:t tags:t toc:t timestamps:t" 776 | :layout "post" 777 | :title "org-trello debug tools" 778 | :description "org-trello debugging tools" 779 | :tags "\n- tools\n- org-trello\n- debug" 780 | :categories "\n- tools\n- org-trello\n- debug" 781 | :permalink "/debug/"))))) 782 | 783 | (ert-deftest test-org2jekyll--alist-to-tuples () 784 | (should (equal 785 | '(("author" "ardumont") 786 | ("startup" "hidestars") 787 | ("options") 788 | ("layout" "post") 789 | ("title" "org-trello debug tools")) 790 | (org2jekyll--alist-to-tuples 791 | '(("author" . "ardumont") 792 | ("startup" "hidestars") 793 | ("options") 794 | ("layout" . "post") 795 | ("title" . "org-trello debug tools")))))) 796 | 797 | (ert-deftest test-org2jekyll-install-yaml-headers () 798 | ;; original-file css should not be modified 799 | (should-not (org2jekyll-install-yaml-headers "something.css" "something.css")) 800 | ;; puslished file as no html should not be published 801 | (should-not (org2jekyll-install-yaml-headers "something.org" "something.else")) 802 | ;; org file should be modified with extra yaml headers 803 | 804 | (should (string= 805 | "--- 806 | date: 2020-05-21 16:58 807 | author: dude 808 | layout: post 809 | title: some-title 810 | excerpt: some-desc 811 | tags: \n- some-tags 812 | categories: \n- some-cat 813 | --- 814 | " 815 | (let ((original-file "/tmp/awesome.org") 816 | (published-file "/tmp/awesome.html")) 817 | (with-temp-file original-file 818 | (insert 819 | "#+STARTUP: showall 820 | #+STARTUP: hidestars 821 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 822 | #+LAYOUT: post 823 | #+AUTHOR: dude 824 | #+DATE: 2020-05-21 Thu 16:58 825 | #+TITLE: some-title 826 | #+DESCRIPTION: some-desc 827 | #+TAGS: some-tags 828 | #+CATEGORIES: some-cat 829 | 830 | Awesome post 831 | ")) 832 | ;; empty file which simulates a published article 833 | (with-temp-file published-file (insert "")) 834 | ;; install yaml headers on the published file 835 | (org2jekyll-install-yaml-headers original-file published-file) 836 | ;; checking the yaml header (there are only those)x 837 | (with-temp-buffer 838 | (insert-file-contents published-file) 839 | (buffer-substring-no-properties (point-min) (point-max)))))) 840 | 841 | (should (string= 842 | "--- 843 | date: 2020-05-21 16:58 844 | author: guy 845 | layout: page 846 | title: this is a page 847 | excerpt: description 848 | tags: \n- tag0\n- tag1 849 | categories: \n- cat0 850 | --- 851 | " 852 | (let ((original-file "/tmp/page.org2jekyll") 853 | (published-file "/tmp/page.html")) 854 | (with-temp-file original-file 855 | (insert 856 | "#+STARTUP: hidestars showall 857 | #+LAYOUT: page 858 | #+AUTHOR: guy 859 | #+DATE: 2020-05-21 Thu 16:58 860 | #+TITLE: this is a page 861 | #+DESCRIPTION: description 862 | #+TAGS: tag0 tag1 863 | #+CATEGORIES: cat0 864 | 865 | Awesome page 866 | ")) 867 | ;; empty file which simulates a published article 868 | (with-temp-file published-file (insert "")) 869 | ;; install yaml headers on the published file 870 | (org2jekyll-install-yaml-headers original-file published-file) 871 | ;; checking the yaml header (there are only those)x 872 | (with-temp-buffer 873 | (insert-file-contents published-file) 874 | (buffer-substring-no-properties (point-min) (point-max))))))) 875 | 876 | (ert-deftest test-org2jekyll-publish () 877 | (should (string= "org2jekyll - published post!" 878 | (org2jekyll-tests-with-temp-buffer 879 | "#+STARTUP: showall 880 | #+STARTUP: hidestars 881 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 882 | #+LAYOUT: post 883 | #+AUTHOR: dude 884 | #+DATE: 2020-05-21 Thu 16:58 885 | #+TITLE: some-title 886 | #+DESCRIPTION: some-desc 887 | #+TAGS: some-tags 888 | #+CATEGORIES: some-cat 889 | 890 | Awesome post 891 | " 892 | (with-mock 893 | (mock (org2jekyll-publish-post nil) => "published post!") 894 | (mock (org2jekyll-publish-web-project) => 'done) 895 | (call-interactively 'org2jekyll-publish))))) 896 | 897 | (should (string= "org2jekyll - published page!" 898 | (org2jekyll-tests-with-temp-buffer 899 | "#+STARTUP: showall 900 | #+STARTUP: hidestars 901 | #+OPTIONS: H:2 num:nil tags:t toc:nil timestamps:t 902 | #+LAYOUT: page 903 | #+AUTHOR: dude 904 | #+DATE: 2020-05-21 Thu 16:58 905 | #+TITLE: some-title 906 | #+DESCRIPTION: some-desc 907 | #+TAGS: some-tags 908 | #+CATEGORIES: some-cat 909 | 910 | Awesome post 911 | " 912 | (with-mock 913 | (mock (org2jekyll-publish-page nil) => "published page!") 914 | (mock (org2jekyll-publish-web-project) => 'done) 915 | (call-interactively 'org2jekyll-publish)))))) 916 | 917 | (ert-deftest test-org2jekyll-publish-posts () 918 | (should (equal '("post.org") 919 | (let ((org2jekyll-jekyll-layout-post "post") 920 | (org2jekyll-jekyll-layout-page "page") 921 | (org-publish-project-alist '(("post" "something")))) 922 | (with-mock 923 | (mock (org-publish-get-base-files '("post" "something")) 924 | => '("post.org")) 925 | (mock (org2jekyll-article-p "post.org") => "post") 926 | (mock (org2jekyll-publish-post "post.org") => "post.org published!") 927 | (call-interactively 'org2jekyll-publish-posts))))) 928 | (should-not (let ((org2jekyll-jekyll-layout-post "post") 929 | (org2jekyll-jekyll-layout-page "page") 930 | (org-publish-project-alist '(("post" "something")))) 931 | (with-mock 932 | (mock (org-publish-get-base-files '("post" "something")) 933 | => '("page.org")) 934 | (mock (org2jekyll-article-p "page.org") => "page") 935 | (call-interactively 'org2jekyll-publish-posts))))) 936 | 937 | (ert-deftest test-org2jekyll-publish-pages () 938 | (should-not 939 | (let ((org2jekyll-jekyll-layout-post "post") 940 | (org2jekyll-jekyll-layout-page "page") 941 | (org-publish-project-alist '(("page" "something-else")))) 942 | (with-mock 943 | (mock (org-publish-get-base-files '("page" "something-else")) 944 | => '("post.org")) 945 | (mock (org2jekyll-article-p "post.org") => "post") 946 | (call-interactively 'org2jekyll-publish-pages)))) 947 | (should 948 | (equal '("page.org") 949 | (let ((org2jekyll-jekyll-layout-post "post") 950 | (org2jekyll-jekyll-layout-page "page") 951 | (org-publish-project-alist '(("page" "something-else")))) 952 | (with-mock 953 | (mock (org-publish-get-base-files '("page" "something-else")) 954 | => '("page.org")) 955 | (mock (org2jekyll-article-p "page.org") => "page") 956 | (mock (org2jekyll-publish-page "page.org") => "page.org published!") 957 | (call-interactively 'org2jekyll-publish-pages)))))) 958 | 959 | (ert-deftest test-org2jekyll-local-link-export () 960 | "Ensure the local link export function works as expected" 961 | (should (string= "org2jekyll - Unknown format pdf, only dealing with html" 962 | (org2jekyll-local-link-export "/some-link" "link description" "pdf"))) 963 | (should (string= "link description" 964 | (org2jekyll-local-link-export "/some-link" "link description" "html"))) 965 | (should (string= "/link" 966 | (org2jekyll-local-link-export "/link" nil "html")))) 967 | 968 | ;;; org2jekyll-test.el ends here 969 | --------------------------------------------------------------------------------