Corrections to article for release. Adds perl script.

- Moves the test-code-document article to a draft.
   It is not ready for publication.
This commit is contained in:
Daniel Lopretto 2020-09-08 12:41:50 -04:00
parent f5db2676df
commit 87031eedad
3 changed files with 162 additions and 7 deletions

45
publishfromwiki.pl Normal file
View File

@ -0,0 +1,45 @@
use strict;
use warnings;
use File::Basename;
use Getopt::Long qw(GetOptions);
my ($path) = shift;
die "Filename Required" unless $path;
my @tags;
my $taglist = "";
GetOptions("tag:s@" => \@tags, "tags:s" => \$taglist);
$taglist = $taglist . ', ' if $taglist;
$taglist = $taglist . join(', ', @tags);
my ($title,$dir,$ext) = fileparse($path, qr/\.[^.]*/);
my @result = qx(hexo --cwd="~/Projects/blog" new post "$title");
my $blogfile = $result[-1];
$blogfile =~ s/INFO Created:\s+([^\r\n]+)[\r\n]/$1/;
$blogfile = glob($blogfile); # expand ~
rename($blogfile, $blogfile.'.bak') or die $!;
open(BLOGIN, '<'.$blogfile.'.bak') or die $!;
open(OUT, '>'.$blogfile) or die $!;
## Copy the Contents of the backup to the blog post rewriting the tags inline
while(my $line = <BLOGIN>)
{
$line =~ s/tags:/tags: [$taglist]/g;
print OUT $line;
}
close(BLOGIN);
open WIKIIN, '<', $path or die $!;
## Copy the Contents of the Wiki file to the blog post
while (my $line = <WIKIIN>) {
print OUT $line;
}
close(WIKIIN);
close(OUT);
unlink $blogfile.'.bak';

View File

@ -0,0 +1,106 @@
---
title: Publish VimWiki to Blog
cwd: ~/Projects/blog
date: 2020-09-02 14:00:15
tags: [Programming, Perl, VimWiki]
---
### What is VimWiki?
I use [VimWiki](https://github.com/vimwiki/vimwiki) as my personal wiki and note taking tool. Sometimes what I write in my wiki I want to public to my [blog](/~timemachine3030). This script aim to do that.
## Requirements
In essence this is just a copy from my `~/vimwiki` folder into my `~/Projects/blogs/source/_posts/` folder. Hexo (my site generator) wants some meta data added to the top of the file, so I'll need to have that included. I'll most likely be in vim, editing the wiki, when I decide to publish it so I can create a vim command to initialize the copy, but I don't want to write the script in vimscript; that would be too much reliance on vim and I want to be able to publish any markdown file.
- Copy first parameter to `~/Projects/blogs/source/_posts/` make configurable if it's easy.
- Add the hexo meta data to the top of the file. There is a template for this in `~/Projects/blogs/scafolds/`
- Add `tags` as switches to the command, as `--tags "Programming, Markdown"` or as `--tag Programming --tag Markdown`
The fun thing about writing requirements for even the smallest of scripts is you get a first shot of thinking about your interface. While looking up the location of hexo's scaffolds folder and thought to my self "I can just use hexo to create the file and then append the vimwiki file to the end". Will that work? Probably, it couples this tool tightly to hexo, but so does using hexo's template format. Uncoupling from the template format is more configuration than I want to do for this small "get some automation in place script".
## I guess bash?
Originally I wanted to write this program in JavaScript and run it in with npm. There are loads of command line argument parsers for node.js and file manipulation is easy. The requirements tell me that two commands should do what I want...
Never mind... The hexo command line tools don't have the ability to add tags from the invocation of `hexo new page ...`.
I could use `sed` to parse the header and write the tags in. I'm not great at `sed` and I would be just copy something off stack overflow to solve the issue. I don't want to do that.
I could write a hexo plugin but that's whole different rabbit hole.
## Maybe Perl?
A fun maxim is: "if bash scripts can get 75% of the way there Perl can finish it"[^1]. You can quote a bash command in backticks (or `px()`) and Perl will run it and return the result. This is not a bad choice considering the short comings I describe in the previous chapter. I don't want to "tool up" for this project so I hope the version of per that ships with MacOS is good enough, `v5.30.0`[^2]
## The Script
(#save publish_from_vimwiki.pl) Process command line arguments
```perl
use strict;
use warnings;
use File::Basename;
use Getopt::Long qw(GetOptions);
my ($path) = shift;
die "Filename Required" unless $path;
my @tags;
my $taglist = "";
GetOptions("tag:s@" => \@tags, "tags:s" => \$taglist);
$taglist = $taglist . ', ' if $taglist;
$taglist = $taglist . join(', ', @tags);
my ($title,$dir,$ext) = fileparse($path, qr/\.[^.]*/);
```
This allows commands like `publish_from_vimwiki.pl ~/vimwiki/somefile.md --tags "SomeTag, Two, Three"` the `GetOpt()` call will look for individual tags in `--tag` or/and a comma separated list of tags in `--tags`. Everything ends up in the `$tagslist` scalar.
(#save publish_from_vimwiki.pl) Create blog post
```perl
my @result = qx(hexo --cwd="~/Projects/blog" new post "$title");
my $blogfile = $result[-1];
$blogfile =~ s/INFO Created:\s+([^\r\n]+)[\r\n]/$1/;
$blogfile = glob($blogfile);
rename($blogfile, $blogfile.'.bak') or die $!;
```
Here we crate the new post, calling `hexo new post` directly. Then munch the results of the hexo command to get the name of the file it created. We make a back of the new post; need to remove that after we are done:
(#save publish_from_vimwiki.pl|cleanup)
```perl
unlink $blogfile.'.bak';
```
Now we can copy the backup file back into the blog post file modifying the tags along the way.
(#save publish_from_vimwiki.pl) Write the header of the blog w/ tags
```perl
open(BLOGIN, '<'.$blogfile.'.bak') or die $!;
open(OUT, '>'.$blogfile) or die $!;
while(my $line = <BLOGIN>) {
$line =~ s/tags:/tags: [$taglist]/g;
print OUT $line;
}
close(BLOGIN);
```
Finally we are ready to append with VimWiki file contents to the blog post.
(#save publish_from_vimwiki.pl)
```perl
open WIKIIN, '<', $path or die $!;
while (my $line = <WIKIIN>) {
print OUT $line;
}
close(WIKIIN);
close(OUT);
```
[^1]: This is never true.
[^2]: It is fine.

View File

@ -69,11 +69,11 @@ There was duplication of effort in building these documents. An outline of a doc
1. Cover page
- Title
- Supported API version
- Supported API [version](version)
- Release date
- Confidentiality statement
2. Detailed change history of document
- A table with the Release Date and Changes
- A table with the Release Date and Changes
3. Document conventions
4. Common error response codes, meanings, examples, and remedies
5. Authentication requirements
@ -163,7 +163,7 @@ Markdown standards don't have or reserve `(#...)` sequences. In general a parent
(#save: parser.js:constants) Regular Expression to capture commands
```javascript
const reCmdCapture = /^\(#(?<cmd>[a-z][a-z_-]+)\s*:\s*["'`](?<fn>[^["'`]+)["'`]\s*:?\s*(?<label>[^\)]*)\)\s*(?<caption>[^\n]*)/;
const reCmdCapture = /^\(#(?<cmd>[a-z][a-z_-]+)\s*:\s*["'`]?(?<purp>[^["'`:]+)["'`]?\s*:?\s*(?<label>[^\)]*)\)\s*(?<caption>[^\n]*)/;
function captureCommand(str) {
const matches = str.match(reCmdCapture)
return matches
@ -174,6 +174,7 @@ function captureCommand(str) {
caption: matches.groups.caption
}
: false;
}
```
@ -181,13 +182,16 @@ That's one way to do it...so is:
(#save: parser.js:constants) Regular Expression to match commands
```javascript
const reCmdMatcher = /^\(#[^)]+\)\s+[^\n]*$/;
const reCmdMatcher = /^\(#[^)]+\)/;
const reSplitOffCaption = /\)\s*/;
const reDirectiveSplitter = /\s*:\s*/;
const reCaptureUnquoted = /^(['"`])?(.+?)\1?$/;
function matchCommand(str) {
const matches = str.match(reCmdMatcher);
if (!!matches) {
let [directive, caption] = str.split(/\)\s*/);
let [command, purpose, label] = directive.substr(2).split(/\s*:\s*/);
purpose = purpose.replace(/['"`]/g, '');
let [directive, caption] = str.split(reSplitOffCaption);
let [command, purpose, label] = directive.substr(2).split(reDirectiveSplitter);
purpose = purpose.match(reCaptureUnquoted)[2];
return { command, purpose, label, caption };
}
return false;