Compare commits

...

66 Commits

Author SHA1 Message Date
dd30002f2d
Modularize spec tests for HTML5-modified converter 2023-11-24 20:37:47 +08:00
ac2c00567e
Add spec tests for video block 2023-11-24 20:35:36 +08:00
6e2c022c45
Add image block for HTML5-modified 2023-11-24 20:31:25 +08:00
bb0e461197
Update fallback text for video block 2023-11-24 20:29:20 +08:00
e0aed2313d
Add autoplay, preload, and metadata attribute for video block 2023-11-24 20:28:52 +08:00
e7e973d1c6
Add sidebar block for HTML5-modified 2023-11-24 11:47:28 +08:00
d868c0964c
Add video block for HTML5-modified 2023-11-24 11:43:33 +08:00
09a93481f0
Add basic Asciidoc conversion with API test for chat block 2023-11-24 11:42:33 +08:00
51d4aa1e99
Update flake description 2023-11-24 11:42:08 +08:00
d704253410
Refactor common functions 2023-11-24 11:34:10 +08:00
a57804d519
Update project README 2023-11-24 11:33:32 +08:00
b2d8534999
Update Rubocop configuration 2023-11-24 11:29:28 +08:00
36dffaf3e4
Add audio block for HTML5-modified 2023-11-24 11:28:07 +08:00
153e110489
Add admonition block for HTML5-modified 2023-11-24 11:23:06 +08:00
74c48a345f
Add spec tests for HTML5-modified converter 2023-11-23 10:48:08 +08:00
a6283b72a1
Convert to Nokogiri for HTML manipulation 2023-11-23 10:11:20 +08:00
66233f04e6
Update flake and devshell 2023-11-17 22:11:13 +08:00
83aad53d74
Add forked bundix to the devshell
Just to make it easier to set up for next time.
2023-11-17 22:02:56 +08:00
887d2a675e
Update dependencies and generate proper gemset.nix
I keep forgetting that I've been generating the gemset.nix file from the
nixpkgs bundix instead of the forked bundix. It is not easy to install
some of the more problematic gems like Nokogiri in this way.
2023-11-17 22:01:24 +08:00
c6f2363ca3
Prepare for next development version 2023-11-16 20:17:25 +08:00
71fe2602c2
Update default custom converter name 2023-11-16 20:16:48 +08:00
586cc8daee
Update chat block attributes 2023-11-16 20:15:57 +08:00
5cb366fb2a
Add modified version of built-in HTML5 converter 2023-11-16 19:40:15 +08:00
f0b69b8af7
Release v1.2.1 2023-11-08 11:40:07 +08:00
8545b63c84
Fix GitHub release step 2023-11-08 11:37:50 +08:00
e2e0da4a33
Release v1.2.0 2023-11-08 11:31:37 +08:00
95e7bc12ec
Restructure modules again 2023-11-08 11:26:58 +08:00
fdcdeb1747
Update flake inputs
Flake lock file updates:

• Updated input 'flake-utils':
    'github:numtide/flake-utils/dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7' (2023-06-25)
  → 'github:numtide/flake-utils/ff7b65b44d01cf9ba6a71320833626af21126384' (2023-09-12)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/5daaa32204e9c46b05cd709218b7ba733d07e80c' (2023-07-06)
  → 'github:NixOS/nixpkgs/ec750fd01963ab6b20ee1f0cb488754e8036d89d' (2023-11-07)
• Updated input 'ruby-nix':
    'github:sagittaros/ruby-nix/b1edcbec13c9f15915a900b1fb87d9c3ef1e882b' (2023-04-17)
  → 'github:sagittaros/ruby-nix/911d5e8584453e1aff0fb85c93aa163dcdd0f3f0' (2023-07-08)
2023-11-08 10:30:30 +08:00
2977870311
Add test and improve handling of subpath for man inline macro 2023-11-07 19:35:29 +08:00
9d3f69be6e
Add Rubocop configuration 2023-11-07 19:19:40 +08:00
6291f3b36d
Update chat block to have its own context
Now, this should be configured with templates which is nice.
2023-11-07 19:19:24 +08:00
5cd7566a88
Update CI automated release 2023-11-07 15:33:24 +08:00
de9f3a0e9c
Restructure extensions with Ruby modules
Also restructured how they're named in the filesystem and the class
names as well.
2023-11-06 22:54:57 +08:00
69c8015292
Add subpath option for man inline macro 2023-11-06 22:07:03 +08:00
2b57ba4594
Update release step for GitHub Actions 2023-11-01 21:28:18 +08:00
850b021209
Release v1.1.0 2023-11-01 21:13:57 +08:00
a95b09a81f
Remove preprocessor extension for git blob include processor
It's pretty useless for outside of the custom setup I've had.
2023-11-01 17:30:56 +08:00
cf8a942011
Add 'issue' attribute for GitLab link inline macro 2023-11-01 17:36:11 +08:00
42454be244
Update chat block output formatting
If there's any formatting here in the first place.
2023-10-29 12:50:05 +08:00
928cd80561
Update the default text for manpages link 2023-10-29 12:49:08 +08:00
924fd9eac5
Change default behavior for creating network requests when caption is unset 2023-10-29 12:48:09 +08:00
bfbea57d6b
Add spec tests for GitLab raw content include processor
Even though, it's untested since I barely use it anymore.
2023-11-01 17:37:08 +08:00
821d5eeb27
Add spec tests for GitHub raw content include processor 2023-10-29 17:40:39 +08:00
33faaeac88
Add spec tests for Git blob include processor 2023-10-29 17:39:30 +08:00
74bb141a79
Add spec tests for Repology link inline macro 2023-10-29 17:37:08 +08:00
60983d0d93
Add spec tests for GitLab link inline macro 2023-10-29 17:36:33 +08:00
389abe4176
Add spec tests for Wikipedia inline macro 2023-10-29 17:27:00 +08:00
e2ca9b57f1
Add spec tests for FDroid link inline macro 2023-10-29 12:40:50 +08:00
89c4313d17
Add spec tests for MusicBrainz link inline macro 2023-10-29 12:27:55 +08:00
657020278c
Add spec tests for Flathub link inline macro 2023-10-29 11:21:59 +08:00
1e0fe61e5b
Add spec tests for man inline macro 2023-10-29 11:09:44 +08:00
c215300500
Add spec tests for chat block 2023-10-29 11:05:49 +08:00
fcb4cb7fde
Add spec tests for GitHub link inline macro 2023-10-29 11:00:16 +08:00
f385772715
Add spec tests for SWHID inline macro 2023-10-29 10:38:31 +08:00
44a71f5fe3
Add Rake tasks for cleaning and testing 2023-10-29 10:38:13 +08:00
ad2834cafe
Setup RSpec 2023-10-29 09:56:43 +08:00
6e5aa75a6b
Add tests with rspec 2023-10-29 09:28:55 +08:00
de3ced3d3a
Update extensions to inherit attributes from parent/document 2023-10-28 21:04:36 +08:00
2495c6a0ac
Update build step for CI 2023-10-28 18:19:01 +08:00
fcb06be49f
Add 'openbsd' option for man inline macro 2023-10-28 18:14:33 +08:00
5ebea76900
Allow git-blob-include-processor to discover other repos
Massive oversight over here which I forgot to update when moving it in
its own repo. Whoops.
2023-10-28 18:11:28 +08:00
5ec7195fc8
Update Gemfile lockfile 2023-07-09 18:32:11 +08:00
a28276ae45
Release v1.0.1 2023-07-09 18:14:14 +08:00
8d59caf6b3
Update the GitHub action for gem release 2023-07-09 18:04:56 +08:00
b052cddf56
Update gemspec metadata
I forgot to update them, whoops.
2023-07-09 18:03:03 +08:00
1faf4d45ec
Fix avatarstype attribute override for chat block 2023-07-09 17:41:00 +08:00
91 changed files with 2769 additions and 1574 deletions

View File

@ -1,25 +0,0 @@
name: Publish gem
on:
push:
branches:
- master
tags:
- v*
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v22
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Release gem
run: |
mkdir -p ~/.gem
cat << EOF > ~/.gem/credentials
---
:github: Bearer ${{ secrets.GITHUB_TOKEN }}
:rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }}
EOF
chmod 0600 ~/.gem/credentials
nix develop -c rake release

21
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Publish gem
on:
push:
tags:
- v*
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DeterminateSystems/magic-nix-cache-action@v2
- uses: DeterminateSystems/nix-installer-action@v6
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- run: nix develop -c rake spec
- name: Release Gem
uses: cadwallion/publish-rubygems-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
RELEASE_COMMAND: nix develop -c rake release

1
.rspec Normal file
View File

@ -0,0 +1 @@
--require ./spec/spec_helper.rb

14
.rubocop.yml Normal file
View File

@ -0,0 +1,14 @@
Metrics/BlockLength:
Enabled: false
Metrics/ClassLength:
Enabled: false
Metrics/MethodLength:
Enabled: false
Metrics/AbcSize:
Enabled: false
Style/ClassAndModuleChildren:
Enabled: false

View File

@ -6,6 +6,70 @@
The guidelines for writing this changelog is based from link:https://common-changelog.org[Common Changelog].
Although, this project doesn't follow the Semantic Versioning convention.
Versioning mostly happens on a whim.
== [1.2.0] - 2023-11-08
=== Added
* Add `subpath` option for man inline macro.
This enables making links to other versions of the online manpage service such as in Debian (i.e., `man:ls[1, subpath=/bookworm]`) ({commit-url}/69c8015292ceb9fab03250109b2c5009605a9a8f[`69c8015`]) (Gabriel Arazas)
* Create an extended converter for HTML5.
This is to handle new blocks with context such as the revamped chat block. ({commit-url}/6291f3b36d44c271a66a5ad88906cb707e291b3d[`6291f3b`])
=== Updated
* Restructure the modules.
There should be no difference in using unless you're using the Asciidoctor API which makes it a complete breaking change. footnote:[So far, no one is aware this extension exists so it shouldn't be. If no user uses the project, is it really a breaking change? :)] ({commit-url}/95e7bc12ecd1e573c94b1322ef1b03dec17e8c70[`95e7bc1`]) (Gabriel Arazas)
* Update the chat block to have its own context.
This makes it configurable with a template. ({commit-url}/6291f3b36d44c271a66a5ad88906cb707e291b3d[`6291f3b`]) (Gabriel Arazas)
== [1.1.0] - 2023-11-01
=== Removed
* Remove preprocessor extension from Git blob include processor.
Thus, `doccontentref` document attribute has been removed. ({commit-url}/a95b09a81f623554e4e747063befcf5a14fd060e[`a95b09a`]) (Gabriel Arazas)
=== Updated
* Update the default behavior of several extensions where it will create a network request in all cases, not just when the caption is unset.
It will now throw an error once it detected no object given from a service.
These extensions are the Flathub link inline macro, the F-Droid link inline macro, and the MusicBrainz link inline macro.
For example, `flathub:com.example.NonExistentApp[example app]` will now throw an error since the given app doesn't exist from Flathub. ({commit-url}/924fd9eac5653a14d6105bc8f27f99fabe955f98[`924fd9e`]) (Gabriel Arazas)
* Revise the default text for manpages for man inline macro. ({commit-url}/928cd80561957a529551e42cad8123840aa6afa0[`928cd80`]) (Gabriel Arazas)
=== Added
* Add 'openbsd' option for man inline macro for easily linking manpages from https://man.openbsd.org. ({commit-url}/fcb06be49fba5d3251e6c68e5fdaf934034dcf41[`fcb06be`]) (Gabriel Arazas)
* Add 'issue' option for GitLab link inline macro enabling users to link to issues from GitLab instances easily. ({commit-url}/cf8a942011cbd6b26785689d0ee4b8eff67f947e[`cf8a942`]) (Gabriel Arazas)
=== Fixed
* Fix the Git repo discovery processor of the Git blob include processor with `gitrepo` attribute.
By default, it will try to discover it through the base directory of the document. ({commit-url}/a95b09a81f623554e4e747063befcf5a14fd060e[`a95b09a`]) (Gabriel Arazas)
* Make the extensions inherit part of the parent's (or if possible, the document) attributes.
This should fix some things such as setting the `avatarstype` document attribute for chat block processor extension. ({commit-url}/de3ced3d3a237870f9d57279649db71feaba975c[`de3ced3`]) (Gabriel Arazas)
== [1.0.1] - 2023-07-09
=== Updated
* Update the gem metadata. (link:{commit-url}/b052cddf56397489c4eb9c7908bfbadbce2c080f[`b052cddf`]) (Gabriel Arazas)
=== Fixed
* Fix the `avatarstype` attribute override for the chat block extension.
This is considered a bug since it is more intended as a project-wide attribute. (link:{commit-url}/1faf4d45ec9891532254867c219ffb5094781948[`1faf4d45`]) (Gabriel Arazas)
== [1.0.0] - 2023-07-07

View File

@ -1,8 +1,10 @@
PATH
remote: .
specs:
asciidoctor-foodogsquared-extensions (1.0.0)
asciidoctor-foodogsquared-extensions (1.3.0)
asciidoctor (~> 2.0)
mime-types (~> 3.0)
nokogiri (~> 1.0)
rugged (~> 1.0)
GEM
@ -10,41 +12,58 @@ GEM
specs:
asciidoctor (2.0.20)
ast (2.4.2)
diff-lcs (1.5.0)
json (2.6.3)
language_server-protocol (3.17.0.3)
mime-types (3.5.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.1003)
nokogiri (1.15.4-x86_64-linux)
racc (~> 1.4)
parallel (1.23.0)
parser (3.2.2.3)
parser (3.2.2.4)
ast (~> 2.4.1)
racc
prettier_print (1.2.1)
racc (1.7.1)
prism (0.17.1)
racc (1.7.3)
rainbow (3.1.1)
rake (13.0.6)
regexp_parser (2.8.1)
rexml (3.2.5)
rubocop (1.54.1)
rake (13.1.0)
regexp_parser (2.8.2)
rexml (3.2.6)
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.6)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.1)
rubocop (1.57.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.2.2.3)
parser (>= 3.2.2.4)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.0, < 2.0)
rubocop-ast (>= 1.28.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.29.0)
rubocop-ast (1.30.0)
parser (>= 3.2.1.0)
ruby-lsp (0.6.2)
ruby-lsp (0.12.3)
language_server-protocol (~> 3.17.0)
sorbet-runtime
syntax_tree (>= 6.1.1, < 7)
prism (>= 0.17.1, < 0.18)
sorbet-runtime (>= 0.5.5685)
ruby-progressbar (1.13.0)
rugged (1.6.3)
sorbet-runtime (0.5.10902)
syntax_tree (6.1.1)
prettier_print (>= 1.2.0)
unicode-display_width (2.4.2)
rugged (1.7.1)
sorbet-runtime (0.5.11139)
unicode-display_width (2.5.0)
PLATFORMS
x86_64-linux
@ -52,8 +71,9 @@ PLATFORMS
DEPENDENCIES
asciidoctor-foodogsquared-extensions!
rake
rspec (~> 3.0)
rubocop
ruby-lsp
BUNDLED WITH
2.4.10
2.4.20

View File

@ -14,6 +14,8 @@ Who knows, parts of the set might develop into a more presentable and stable ext
The extension is required to be used with Ruby 3.0 and above.
(At least until I can test and confirm it works on the previous versions.)
For now, it explicitly supports CRuby and that's it. footnote:[Mainly due to Nokogiri but I'll look for other HTML processors.]
In order to use it, you have to install it first in your Ruby environment.
It is available as a gem in RubyGems as `asciidoctor-foodogsquared-extensions` so you can add the following line in `Gemfile`.

View File

@ -1,8 +1,11 @@
# frozen_string_literal: true
require 'rake/clean'
require 'bundler/gem_tasks'
require 'rubocop/rake_task'
require 'rspec/core/rake_task'
RuboCop::RakeTask.new
RSpec::Core::RakeTask.new
task default: :rubocop

View File

@ -1,22 +1,26 @@
Gem::Specification.new do |s|
s.name = 'asciidoctor-foodogsquared-extensions'
s.version = '1.0.0'
s.version = '1.3.0'
s.licenses = ['MIT']
s.summary = "foo-dogsquared's custom Asciidoctor extensions"
s.description = <<-DESC
foo-dogsquared's custom Asciidoctor extensions as a Gem. This is not meant
to be used in production or as a public Gem. This is used since Hugo
doesn't allow loading Asciidoctor extensions with path separators.
foo-dogsquared's set of Asciidoctor extensions as a Gem. This is where I
implemented several pet features that will most likely never be a part of
Asciidoctor.
DESC
s.required_ruby_version = '>= 3.0.0'
s.authors = ['Gabriel Arazas']
s.email = 'foodogsquared@foodogsquared.one'
s.metadata = { 'source_code_uri' => 'https://github.com/foo-dogsquared/foo-dogsquared.github.io' }
s.metadata = { 'source_code_uri' => 'https://github.com/foo-dogsquared/asciidoctor-foodogsquared-extensions' }
s.files = Dir['lib/**/*', '*.gemspec']
s.files = Dir['lib/**/*', '*.gemspec', 'LICENSE', 'CHANGELOG.adoc', 'README.adoc']
s.add_runtime_dependency 'asciidoctor', '~> 2.0'
s.add_runtime_dependency 'mime-types', '~> 3.0'
s.add_runtime_dependency 'nokogiri', '~> 1.0'
s.add_runtime_dependency 'rugged', '~> 1.0'
s.add_development_dependency 'rspec', '~> 3.0'
end

45
flake.lock generated
View File

@ -5,11 +5,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1687709756,
"narHash": "sha256-Y5wKlQSkgEK2weWdOu4J3riRd+kV/VCgHsqLNTTWQ/0=",
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1688646010,
"narHash": "sha256-kCeza5eKI2NEi8k0EoeZfv3lN1r1Vwx+L/VA6I8tmG4=",
"lastModified": 1699343069,
"narHash": "sha256-s7BBhyLA6MI6FuJgs4F/SgpntHBzz40/qV0xLPW6A1Q=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5daaa32204e9c46b05cd709218b7ba733d07e80c",
"rev": "ec750fd01963ab6b20ee1f0cb488754e8036d89d",
"type": "github"
},
"original": {
@ -38,7 +38,8 @@
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"ruby-nix": "ruby-nix"
"ruby-nix": "ruby-nix",
"ruby-nix-bundix": "ruby-nix-bundix"
}
},
"ruby-nix": {
@ -48,19 +49,39 @@
]
},
"locked": {
"lastModified": 1681695382,
"narHash": "sha256-RBZnSdx3dnUg3o+FiQVKKeKZN6pntYb19mXnnA5b/i8=",
"owner": "sagittaros",
"lastModified": 1688825976,
"narHash": "sha256-7EvZu+/+uNZ0kfSgQQIrRGg8RXcUN9UgRsobjbxEdBQ=",
"owner": "inscapist",
"repo": "ruby-nix",
"rev": "b1edcbec13c9f15915a900b1fb87d9c3ef1e882b",
"rev": "911d5e8584453e1aff0fb85c93aa163dcdd0f3f0",
"type": "github"
},
"original": {
"owner": "sagittaros",
"owner": "inscapist",
"repo": "ruby-nix",
"type": "github"
}
},
"ruby-nix-bundix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1688825865,
"narHash": "sha256-7HP6amLkY3u2NvPguanIW/gugUvGsmY5OMY6tKpjMrA=",
"owner": "inscapist",
"repo": "bundix",
"rev": "5cb01869cb09fb367c02527b1f66707fb9277076",
"type": "github"
},
"original": {
"owner": "inscapist",
"repo": "bundix",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,

View File

@ -1,12 +1,15 @@
{
description = "Basic flake template for setting up development shells";
description = "Flake for setting up asciidoctor-foodogsquared-extensions";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
ruby-nix.url = "github:sagittaros/ruby-nix";
ruby-nix.url = "github:inscapist/ruby-nix";
ruby-nix.inputs.nixpkgs.follows = "nixpkgs";
ruby-nix-bundix.url = "github:inscapist/bundix";
ruby-nix-bundix.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = inputs@{ self, ruby-nix, nixpkgs, ... }:
@ -14,10 +17,24 @@
in inputs.flake-utils.lib.eachSystem systems (system:
let
pkgs = import nixpkgs { inherit system; };
gems = ruby-nix.lib pkgs {
name = "asciidoctor-foodogsquared-extensions";
ruby = pkgs.ruby_3_1;
gemset = ./gemset.nix;
};
in
{
devShells.default =
import ./shell.nix { inherit pkgs ruby-nix; };
import ./shell.nix {
inherit pkgs;
extraBuildInputs = [
gems.env
gems.ruby
];
extraPackages = [
inputs.ruby-nix-bundix.packages."${system}".default
];
};
formatter = pkgs.treefmt;
});

View File

@ -5,19 +5,22 @@
source = {
remotes = ["https://rubygems.org"];
sha256 = "0yblqlbix3is5ihiqrpbfazb44in7ichfkjzdbsqibp48paanpl3";
target = "ruby";
type = "gem";
};
targets = [];
version = "2.0.20";
};
asciidoctor-foodogsquared-extensions = {
dependencies = ["asciidoctor" "rugged"];
dependencies = ["asciidoctor" "mime-types" "nokogiri" "rugged"];
groups = ["default"];
platforms = [];
source = {
path = ./.;
path = ".";
type = "path";
};
version = "1.0.0";
targets = [];
version = "1.3.0";
};
ast = {
groups = ["default" "lint"];
@ -25,18 +28,34 @@
source = {
remotes = ["https://rubygems.org"];
sha256 = "04nc8x27hlzlrr5c2gn7mar4vdr0apw5xg22wp6m8dx3wqr04a0y";
target = "ruby";
type = "gem";
};
targets = [];
version = "2.4.2";
};
diff-lcs = {
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0rwvjahnp7cpmracd8x732rjgnilqv2sx7d1gfrysslc3h039fa9";
target = "ruby";
type = "gem";
};
targets = [];
version = "1.5.0";
};
json = {
groups = ["default" "lint"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0nalhin1gda4v8ybk6lq8f407cgfrj6qzn234yra4ipkmlbfmal6";
target = "ruby";
type = "gem";
};
targets = [];
version = "2.6.3";
};
language_server-protocol = {
@ -45,18 +64,62 @@
source = {
remotes = ["https://rubygems.org"];
sha256 = "0gvb1j8xsqxms9mww01rmdl78zkd72zgxaap56bhv8j45z05hp1x";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.17.0.3";
};
mime-types = {
dependencies = ["mime-types-data"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0q8d881k1b3rbsfcdi3fx0b5vpdr5wcrhn88r2d9j7zjdkxp5mw5";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.5.1";
};
mime-types-data = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0yjv0apysnrhbc70ralinfpcqn9382lxr643swp7a5sdwpa9cyqg";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.2023.1003";
};
nokogiri = {
dependencies = ["racc"];
groups = ["default"];
platforms = [];
source = null;
targets = [{
remotes = ["https://rubygems.org"];
sha256 = "0hhqzm7p4lww7v3i33im26bmiryfqr0p3iknbadyv5ypf8yysb47";
target = "x86_64-linux";
targetCPU = "x86_64";
targetOS = "linux";
type = "gem";
}];
version = "1.15.4";
};
parallel = {
groups = ["default" "lint"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0jcc512l38c0c163ni3jgskvq1vc3mr8ly5pvjijzwvfml9lf597";
target = "ruby";
type = "gem";
};
targets = [];
version = "1.23.0";
};
parser = {
@ -65,30 +128,36 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1swigds85jddb5gshll1g8lkmbcgbcp9bi1d4nigwvxki8smys0h";
sha256 = "0r69dbh6h6j4d54isany2ir4ni4gf2ysvk3k44awi6amz18nggpd";
target = "ruby";
type = "gem";
};
version = "3.2.2.3";
targets = [];
version = "3.2.2.4";
};
prettier_print = {
prism = {
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1ybgks9862zmlx71zd4j20ky86fsrp6j6m0az4hzzb1zyaskha57";
sha256 = "1kfb29152jd9glga3w06ljcfzkb63yfhrviihibwvbin5kgqcgz6";
target = "ruby";
type = "gem";
};
version = "1.2.1";
targets = [];
version = "0.17.1";
};
racc = {
groups = ["default" "lint"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "11v3l46mwnlzlc371wr3x6yylpgafgwdf0q7hc7c1lzx6r414r5g";
sha256 = "01b9662zd2x9bp4rdjfid07h09zxj7kvn7f5fghbqhzc625ap1dp";
target = "ruby";
type = "gem";
};
version = "1.7.1";
targets = [];
version = "1.7.3";
};
rainbow = {
groups = ["default" "lint"];
@ -96,8 +165,10 @@
source = {
remotes = ["https://rubygems.org"];
sha256 = "0smwg4mii0fm38pyb5fddbmrdpifwv22zv3d3px2xx497am93503";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.1.1";
};
rake = {
@ -105,30 +176,100 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "15whn7p9nrkxangbs9hh75q585yfn66lv0v2mhj6q6dl6x8bzr2w";
sha256 = "1ilr853hawi09626axx0mps4rkkmxcs54mapz9jnqvpnlwd3wsmy";
target = "ruby";
type = "gem";
};
version = "13.0.6";
targets = [];
version = "13.1.0";
};
regexp_parser = {
groups = ["default" "lint"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "136br91alxdwh1s85z912dwz23qlhm212vy6i3wkinz3z8mkxxl3";
sha256 = "1d9a5s3qrjdy50ll2s32gg3qmf10ryp3v2nr5k718kvfadp50ray";
target = "ruby";
type = "gem";
};
version = "2.8.1";
targets = [];
version = "2.8.2";
};
rexml = {
groups = ["default" "lint"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "08ximcyfjy94pm1rhcx04ny1vx2sk0x4y185gzn86yfsbzwkng53";
sha256 = "05i8518ay14kjbma550mv0jm8a6di8yp5phzrd8rj44z9qnrlrp0";
target = "ruby";
type = "gem";
};
version = "3.2.5";
targets = [];
version = "3.2.6";
};
rspec = {
dependencies = ["rspec-core" "rspec-expectations" "rspec-mocks"];
groups = ["development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "171rc90vcgjl8p1bdrqa92ymrj8a87qf6w20x05xq29mljcigi6c";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.12.0";
};
rspec-core = {
dependencies = ["rspec-support"];
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0l95bnjxdabrn79hwdhn2q1n7mn26pj7y1w5660v5qi81x458nqm";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.12.2";
};
rspec-expectations = {
dependencies = ["diff-lcs" "rspec-support"];
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "05j44jfqlv7j2rpxb5vqzf9hfv7w8ba46wwgxwcwd8p0wzi1hg89";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.12.3";
};
rspec-mocks = {
dependencies = ["diff-lcs" "rspec-support"];
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1gq7gviwpck7fhp4y5ibljljvxgjklza18j62qf6zkm2icaa8lfy";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.12.6";
};
rspec-support = {
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1ky86j3ksi26ng9ybd7j0qsdf1lpr8mzrmn98yy9gzv801fvhsgr";
target = "ruby";
type = "gem";
};
targets = [];
version = "3.12.1";
};
rubocop = {
dependencies = ["json" "language_server-protocol" "parallel" "parser" "rainbow" "regexp_parser" "rexml" "rubocop-ast" "ruby-progressbar" "unicode-display_width"];
@ -136,10 +277,12 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1vklabd0510isqhikx4bfx5qn9g8pyj8h9jxryayp2wj8mx4kg74";
sha256 = "06qnp5zs233j4f59yyqrg8al6hr9n4a7vcdg3p31v0np8bz9srwg";
target = "ruby";
type = "gem";
};
version = "1.54.1";
targets = [];
version = "1.57.2";
};
rubocop-ast = {
dependencies = ["parser"];
@ -147,21 +290,25 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "188bs225kkhrb17dsf3likdahs2p1i1sqn0pr3pvlx50g6r2mnni";
sha256 = "1cs9cc5p9q70valk4na3lki4xs88b52486p2v46yx3q1n5969bgs";
target = "ruby";
type = "gem";
};
version = "1.29.0";
targets = [];
version = "1.30.0";
};
ruby-lsp = {
dependencies = ["language_server-protocol" "sorbet-runtime" "syntax_tree"];
dependencies = ["language_server-protocol" "prism" "sorbet-runtime"];
groups = ["development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "03jx0157jpfrnww5ww6hnkprgzfv4m7ahiqzpjdjjrcb67jp5nh1";
sha256 = "0rs5vd93il0hz1c2dl6j0mf7hgw1mw3k2vjmg0xnzh90rg6q57g4";
target = "ruby";
type = "gem";
};
version = "0.6.2";
targets = [];
version = "0.12.3";
};
ruby-progressbar = {
groups = ["default" "lint"];
@ -169,8 +316,10 @@
source = {
remotes = ["https://rubygems.org"];
sha256 = "0cwvyb7j47m7wihpfaq7rc47zwwx9k4v7iqd9s1xch5nm53rrz40";
target = "ruby";
type = "gem";
};
targets = [];
version = "1.13.0";
};
rugged = {
@ -178,40 +327,35 @@
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "016bawsahkhxx7p8azxirpl7y2y7i8a027pj8910gwf6ipg329in";
sha256 = "02m9zksfy3dwzhbv56xq2wwmlghca5209hdg895pi2x2d2sbkahi";
target = "ruby";
type = "gem";
};
version = "1.6.3";
targets = [];
version = "1.7.1";
};
sorbet-runtime = {
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0csmpdf05wp9ndb61vsnpbw2vkxsm888h2xwrddcz0p02laiz7s8";
sha256 = "1krfwpmvbzamlmw8p0cyyma53byvxw1mgg109dxnpfl3gdpknw45";
target = "ruby";
type = "gem";
};
version = "0.5.10902";
};
syntax_tree = {
dependencies = ["prettier_print"];
groups = ["default" "development"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "162m5xhbiq315bncp49ziddws537dv09pqsgrzsrmhhsymhgy0zb";
type = "gem";
};
version = "6.1.1";
targets = [];
version = "0.5.11139";
};
unicode-display_width = {
groups = ["default" "lint"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1gi82k102q7bkmfi7ggn9ciypn897ylln1jk9q67kjhr39fj043a";
sha256 = "1d0azx233nags5jx3fqyr23qa2rhgzbhv8pxp46dgbg1mpf82xky";
target = "ruby";
type = "gem";
};
version = "2.4.2";
targets = [];
version = "2.5.0";
};
}
}

View File

@ -1,3 +1,4 @@
# frozen_string_literal: true
require 'asciidoctor/foodogsquared-extensions'
require 'asciidoctor/foodogsquared/extensions'
require 'asciidoctor/foodogsquared/converter'

View File

@ -1,115 +0,0 @@
= Chat block processor
:toc:
A link:https://docs.asciidoctor.org/asciidoctor/latest/extensions/block-processor/[block processor] that adds a a dialog box style to the block.
Exclusive to the HTML backend.
== Synopsis
....
[chat, $AVATARNAME, $AVATARSTATE, $ATTRS...]
====
$CONTENT
====
....
The avatar name is the name of the folder to be retrieved from the `avatarsdir` attribute.
The directory enforces a certain structure which can be seen in <<extra-notes>>.
Both the avatar name and the state are to be converted to snake case (e.g., `El Pablo` to `el_pablo`) for the image path.
== Attributes
* `avatarsdir` is the folder containing the avatars' stickers.
This is explained in detail from the <<extra-notes>> section.
* `avatarstype` is similar to `icontype` attribute except this is used for the avatar stickers.
The default value is `webp`.
* `state` is the sticker to be retrieved from the avatars directory.
It has a default value of `default`.
You could also use this attribute instead of the `$AVATARSTATE` positional argument for whatever reason.
* `name` is the canonical name of the avatar.
This is used for titles and alts in the internal image block.
By default, this is the same as the given avatar.
[#extra-notes]
== Extra notes
This component has some prerequisites for this to fully work specifically with `avatarsdir` attribute that contains a list of avatars and their stickers.
By default, this value is at the `avatars` subdirectory of the `iconsdir` attribute.
It is recommended to set this value yourself.
+
--
This enforces a certain structure where the root directory contains a list of folders representing the avatar with each of the folder containing stickers which represents their state.
For example, here's what `avatarsdir` could contain following the expected structure.
[source]
----
./static/icons/avatars/
├── ezran/
│ ├── crisis.webp
│ ├── default.webp
│ ├── sad.webp
│ └── shocked.webp
└── foodogsquared/
├── crisis.webp
├── default.webp
├── sad.webp
└── shocked.webp
----
--
== Example usage
Let's assume `avatarsdir` is set to the `static/icons/avatars` with the following file structure.
[source]
----
./static/icons/avatars/
├── ezran/
│ ├── crisis.webp
│ ├── default.webp
│ ├── sad.webp
│ └── shocked.webp
├── el-pablo/
│ ├── crisis.webp
│ ├── default.webp
│ ├── ghastly.webp
│ ├── melodramatic.webp
│ ├── sad.webp
│ └── shocked.webp
└── foodogsquared/
├── crisis.webp
├── default.webp
├── sad.webp
└── shocked.webp
----
- The following block should get the default image for `foodogsquared` which is in `./static/icons/avatars/foodogsquared/default.webp`.
+
....
[chat, foodogsquared]
====
Hello there!
====
....
- The following block should contain El Pablo's melodramatic dialog state.
Take note of the resulting path for the image which is in kebab-case.
+
....
[chat, El Pablo, state=melodramatic]
====
What tragedy is happening here!
I couldn't take it.
__Please__.
====
....

View File

@ -1,56 +0,0 @@
# frozen_string_literal: true
class ChatBlock < Asciidoctor::Extensions::BlockProcessor
use_dsl
named :chat
on_context :example
name_positional_attributes 'avatar', 'state'
default_attributes 'state' => 'default', 'avatarstype' => 'avif'
def process(parent, reader, attrs)
block = create_block parent, :pass, nil, attrs, content_model: :compound
block.add_role('dialogblock')
# You can think of this section as a pipeline constructing the HTML
# component for this block. Specifically, we're building one component that
# contains two output: the dialog image of our avatar and its content.
attrs['name'] ||= attrs['avatar']
block << (create_html_fragment block, %(
<div role="figure" class="dialogblock dialogblock__box dialogblock__avatar--#{attrs['avatar']} #{attrs['role']}">
<div class="dialogblock dialogblock__avatar">
))
attrs['avatarsdir'] ||= File.expand_path('./avatars', attrs['iconsdir'])
avatar_sticker = "#{attrs['avatar'].to_kebab}/#{attrs['state'].to_kebab}.#{attrs['avatarstype']}"
avatar_img_attrs = {
'target' => parent.image_uri(avatar_sticker, 'avatarsdir'),
'alt' => attrs['name']
}
avatar_imgblock = create_image_block block, avatar_img_attrs
block << avatar_imgblock
block << (create_html_fragment block, %(
</div>
<div class="dialogblock dialogblock__text">
<small class="dialogblock dialogblock__avatar-name">#{attrs['name']}</small>
))
parse_content block, reader
block << (create_html_fragment block, %(
</div>
</div>
))
block
end
private
def create_html_fragment(parent, html, attributes = nil)
create_block parent, :pass, html, attributes
end
end

View File

@ -1,36 +0,0 @@
= F-droid link inline macro
:toc:
An inline macro as a shorthand for F-droid links.
== Synopsis
[source, asciidoc]
----
fdroid:$APP_ID[$CAPTION]
----
Where...
- `$APP_ID` is the application ID of the program (e.g., `org.moire.ultrasonic`).
- `$CAPTION` is the link text.
By default, it will use the display name of the application from its link:https://gitlab.com/fdroid/fdroiddata/[metadata repository].
In other words, it will create an additional network request.
== Attributes
- `lang` is the language page to be linked.
By default, it links to the English page of `en`.
== Example usage
- `fdroid:org.moire.ultrasonic[]` should link to the link:https://f-droid.org/en/packages/org.moire.ultrasonic/[F-Droid page for Ultrasonic] with the link text 'Ultrasonic'.
- `fdroid:org.moire.ultrasonic[Hello there]` is the same as previous item but with the link text replaced with 'Hello there'.
- `fdroid:org.moire.ultrasonic[lang=it]` is the same as the first list item but links to the link:https://f-droid.org/it/packages/org.moire.ultrasonic/[Italian page].

View File

@ -1,28 +0,0 @@
# frozen_string_literal: true
require 'open-uri'
require 'yaml'
class FDroidLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :fdroid
name_positional_attributes 'caption'
default_attributes 'lang' => 'en'
def process(parent, target, attrs)
doc = parent.document
app_id = target
app_metadata_uri = %(https://gitlab.com/fdroid/fdroiddata/-/raw/master/metadata/#{app_id}.yml)
if attrs['caption'].nil?
metadata = OpenURI.open_uri(app_metadata_uri) { |f| YAML.safe_load(f.read) }
attrs['caption'] = metadata['AutoName']
end
url = %(https://f-droid.org/#{attrs['lang']}/packages/#{app_id})
doc.register :links, url
create_anchor parent, attrs['caption'], type: :link, target: url
end
end

View File

@ -1,28 +0,0 @@
= Flathub link inline macro
:toc:
A shorthand for linking applications from link:https://flathub.org[FlatHub].
== Synopsis
[source, asciidoc]
----
flathub:$APP_ID[$CAPTION]
----
Where...
- `$APP_ID` is the application ID of the program on Flathub.
- `$CAPTION` is the link text to be used.
By default, it will get the appstream metadata from FlatHub and use the display name.
Take note it creates an additional network request to get the name.
== Example usage
- `flathub:org.gnome.design.IconLibrary[]` links to the link:https://flathub.org/apps/org.gnome.design.IconLibrary[FlatHub page of GNOME Icon Library] with `Icon Library` as the link text.
- `flathub:org.gnome.design.IconLibrary[GNOME Icon Library]` is the same as the previous list item but with its link text replaced with `GNOME Icon Library`.

View File

@ -1,35 +0,0 @@
# frozen_string_literal: true
require 'json'
require 'open-uri'
class FlathubLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :flathub
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
# FlatHub API seems to have no documentation aside from the source code.
# You can easily infer the API with its source code at
# https://github.com/flathub/website.
app_id = target
app_metadata_uri = %(https://flathub.org/api/v2/appstream/#{app_id})
headers = {
'Accept' => 'application/json',
'User-Agent' => ::Asciidoctor::FoodogsquaredCustomExtensions::USER_AGENT
}
if attrs['caption'].nil?
metadata = OpenURI.open_uri(app_metadata_uri, headers) { |f| JSON.parse(f.read) }
attrs['caption'] = metadata['name']
end
url = %(https://flathub.org/apps/#{app_id})
doc.register :links, url
create_anchor parent, attrs['caption'], type: :link, target: url
end
end

View File

@ -1,56 +0,0 @@
# frozen_string_literal: true
require 'asciidoctor'
require 'asciidoctor/extensions'
require_relative 'helpers'
require_relative 'man-inline-macro/extension'
require_relative 'swhid-inline-macro/extension'
require_relative 'swhid-include-processor/extension'
require_relative 'github-link-inline-macro/extension'
require_relative 'github-raw-content-include-processor/extension'
require_relative 'gitlab-link-inline-macro/extension'
require_relative 'gitlab-raw-content-include-processor/extension'
require_relative 'chat-block-processor/extension'
require_relative 'git-blob-include-processor/extension'
require_relative 'wikipedia-inline-macro/extension'
require_relative 'package-indices-link-macro/extension'
require_relative 'fdroid-link-inline-macro/extension'
require_relative 'musicbrainz-link-inline-macro/extension'
require_relative 'flathub-link-inline-macro/extension'
require_relative 'repology-link-inline-macro/extension'
require_relative 'ietf-rfc-link-inline-macro/extension'
Asciidoctor::Extensions.register do
inline_macro ManInlineMacro
inline_macro IETFRFCLinkInlineMacro
block ChatBlock if @document.basebackend? 'html'
inline_macro SWHInlineMacro
include_processor SWHIDIncludeProcessor
inline_macro GitHubLinkInlineMacro
include_processor GitHubRawIncludeProcessor
inline_macro GitLabLinkInlineMacro
include_processor GitLabRawIncludeProcessor
include_processor GitBlobIncludeProcessor
preprocessor GitContentBranchAttributePreprocessor
inline_macro WikipediaInlineMacro
# Package indices
inline_macro CtanLinkInlineMacro
inline_macro PypiLinkInlineMacro
inline_macro CratesIOLinkInlineMacro
# App stores
inline_macro FDroidLinkInlineMacro
inline_macro FlathubLinkInlineMacro
# Databases
inline_macro MusicBrainzLinkInlineMacro
inline_macro RepologyLinkInlineMacro
end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
# foodogsquared's custom converter that is an extended version of the built-in
# HTML5 converter. It features custom blocks as well as their preferred output
# for certain blocks.
module Asciidoctor::Foodogsquared::Converter
class Html5Extended < (Asciidoctor::Converter.for 'html5')
register_for 'html5'
def convert_chat(node)
attributes = add_attributes node
avatar_uri = node.parent.image_uri "#{node.attr 'avatarsticker'}/#{node.attr 'state'}.#{node.attr 'avatarstype'}", 'avatarsdir'
<<~HTML
<div role="figure" #{attributes.join ' '}>
<div class="dialogblock-avatar">
<img src="#{avatar_uri}" alt="#{node.attributes['avatar']}">
</div>
<div class="dialogblock-text">
<small>#{node.attributes['avatar']}</small>
#{node.content}
</div>
</div>
HTML
end
def add_attributes(node)
attributes = []
attributes << %(id="#{node.id}") if node.id
attributes << %(class="#{node.role}") if node.role
attributes
end
end
end

View File

@ -0,0 +1,266 @@
# frozen_string_literal: true
require 'nokogiri'
require 'mime/types'
module Asciidoctor::Foodogsquared::Converters
# A modified version of the built-in HTML5 converter. This is separated with
# the default project converter that should only contain new blocks to
# prevent overriding the converter that most likely going to trip up the
# user.
#
# Take note this is only intended for the author. The user has to explicitly
# require them somewhere to make use of this.
class HTML5Modified < Asciidoctor::Foodogsquared::Converter::Html5Extended
register_for 'html5'
def convert_paragraph(node)
html = Nokogiri::XML::DocumentFragment.parse '<p></p>'
paragraph = html.first_element_child
add_common_attributes node, paragraph
if node.title?
title = html.document.create_element 'strong', class: 'title'
title.content = node.captioned_title
paragraph.add_child title
end
paragraph.inner_html += node.content
html.to_html
end
def convert_admonition(node)
html = Nokogiri::XML::DocumentFragment.parse '<aside></aside>'
aside = html.first_element_child
aside['data-admonition-type'] = node.attr 'name'
add_common_attributes node, aside
if node.document.attr? 'icons', 'image'
html.document.create_element 'svg' do |svg|
html.document.create_element 'use' do |use|
use['href'] = "#{node.image_uri "#{node.attr 'name'}.svg", 'iconsdir'}##{node.attr 'name'}"
use['alt'] = node.attr 'textlabel'
svg.add_child use
end
aside.add_child svg
end
else
html.document.create_element 'div' do |div|
div.add_class 'admonition-label'
div.content = node.attr 'textlabel'
aside.add_child div
end
end
if node.title?
html.document.create_element 'strong', class: 'title' do |strong|
strong.add_class 'title'
strong.content = node.captioned_title
aside.add_child strong
end
end
aside.inner_html += node.content
html.to_html(indent: 2)
end
def convert_sidebar(node)
html = Nokogiri::XML::DocumentFragment.parse '<aside></aside>'
aside = html.first_element_child
add_common_attributes node, aside
if node.title?
html.document.create_element 'strong' do |strong|
strong.add_class 'title'
strong.content = node.captioned_title
aside.add_child strong
end
end
aside.inner_html += node.content
html.to_html(indent: 2)
end
def convert_image(node)
html = Nokogiri::HTML5::DocumentFragment.parse <<~HTML
<figure>
<picture></picture>
</figure>
HTML
figure = html.first_element_child
picture = figure.first_element_child
add_common_attributes node, figure
node.attr?('sources') && add_sources_elem(node, picture, 'image')
target = node.attr 'target'
if (node.attr?('format', 'svg') || target.end_with?('.svg'))
if node.option? 'inline'
reader_opts = {
start: node.document.attr('imagesdir'),
normalize: true,
label: 'SVG',
warn_if_empty: true
}
figure.inner_html = node.read_contents target, reader_opts
elsif node.option? 'interactive'
picture.unlink
html.document.create_element 'object' do |object|
node.attr?('fallback') && object.add_child(add_img_elem(node, html))
add_attributes_from_node node, object, %w[width height]
object['type'] = 'image/svg+xml'
object['data'] = node.image_uri target
figure.add_child object
end
else
picture.add_child(add_img_elem(node, html))
end
else
picture.add_child(add_img_elem(node, html))
end
if node.title?
html.document.create_element 'figcaption' do |block|
block.inner_html = node.captioned_title
figure.add_child block
end
end
html.to_html(indent: 2)
end
# A modified version of the audio node except it can accept multiple
# sources.
def convert_audio(node)
html = Nokogiri::HTML5::DocumentFragment.parse <<~HTML
<figure>
<audio></audio>
</figure>
HTML
figure = html.first_element_child
audio = figure.first_element_child
add_common_attributes node, figure
add_boolean_attribute node, audio, %w[loop controls muted]
if node.attr? 'sources'
_, sources = add_sources_elem node, audio, 'audio'
sources_download_links = sources.map do |src|
%(<a href="#{src}">#{src}</a>)
end
fallback_text = html.document.parse "Download the audio at #{sources_download_links.join ', '}."
else
audio['src'] = node.attr 'target'
fallback_text = html.document.parse "Download the audio at #{node.attr 'target'}."
end
audio.add_child fallback_text
if node.title?
html.document.create_element 'figcaption' do |block|
block.inner_html = node.captioned_title
figure.add_child block
end
end
html.to_html(indent: 2)
end
# A modified version of the video block except it can accept multiple
# sources with the `sources` attribute. Also, much of the built-in
# Asciidoctor capabilities such as the ability to quickly link from YouTube
# are removed.
def convert_video(node)
html = Nokogiri::HTML5::DocumentFragment.parse <<~HTML
<figure>
<video></video>
</figure>
HTML
figure = html.first_element_child
video = figure.first_element_child
add_common_attributes node, figure
add_boolean_attribute node, video, %w[autoplay loop controls muted]
add_attributes_from_node node, video, %w[width height poster preload]
if node.attr? 'sources'
_, sources = add_sources_elem node, video, 'video'
sources_download_links = sources.map do |src|
%(<a href="#{src}">#{src}</a>)
end
fallback_text = html.document.parse "Download the video at #{sources_download_links.join ', '}."
else
video['src'] = node.attr 'target'
link = %(<a href="#{node.attr 'target'}">#{node.attr 'target'}</a>)
fallback_text = html.document.parse "Download the video at #{link}."
end
video.add_child fallback_text
if node.title?
html.document.create_element 'figcaption' do |block|
block.inner_html = node.captioned_title
figure.add_child block
end
end
html.to_html(indent: 2)
end
def add_common_attributes(node, html)
html['id'] = node.id if node.id
html.add_class node.role unless node.role.nil?
html
end
def add_attributes_from_node(node, html, options)
options.each do |option|
html[option] = node.attr option if node.attr? option
end
html
end
def add_boolean_attribute(node, html, options)
options.each do |option|
html[option] = option if node.option? option
end
html
end
def add_sources_elem(node, html, media_type)
src_attr = html.name == 'picture' ? 'srcset' : 'src'
sources = node.attr('sources', '').split(',').each do |src|
src = html.document.create_element 'source' do |block|
block[src_attr] = src
type = MIME::Types.type_for(src).find do |mime|
mime.media_type == media_type
end
block['type'] = type unless media_type.nil?
end
html.add_child src
end
[html, sources]
end
def add_img_elem(node, html)
html.document.create_element 'img' do |img|
add_attributes_from_node node, img, %w[width height]
img['src'] = node.attr 'target'
img['alt'] = node.alt
end
end
end
end

View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
require 'asciidoctor'
require 'asciidoctor/extensions'
require_relative 'helpers'
require_relative 'extensions/man-inline-macro'
require_relative 'extensions/swhid-inline-macro'
require_relative 'extensions/swhid-include-processor'
require_relative 'extensions/github-inline-macro'
require_relative 'extensions/github-include-processor'
require_relative 'extensions/gitlab-inline-macro'
require_relative 'extensions/gitlab-include-processor'
require_relative 'extensions/chat-block'
require_relative 'extensions/git-blob-include-processor'
require_relative 'extensions/wikipedia-inline-macro'
require_relative 'extensions/package-indices-macro'
require_relative 'extensions/fdroid-inline-macro'
require_relative 'extensions/musicbrainz-inline-macro'
require_relative 'extensions/flathub-inline-macro'
require_relative 'extensions/repology-inline-macro'
require_relative 'extensions/ietf-rfc-inline-macro'
include Asciidoctor::Foodogsquared::Extensions
Asciidoctor::Extensions.register do
inline_macro ManInlineMacro
inline_macro IETFRFCInlineMacro
block ChatBlock if @document.basebackend? 'html'
inline_macro SWHInlineMacro
include_processor SWHIncludeProcessor
inline_macro GitHubInlineMacro
include_processor GitHubIncludeProcessor
inline_macro GitLabInlineMacro
include_processor GitLabIncludeProcessor
include_processor GitBlobIncludeProcessor
inline_macro WikipediaInlineMacro
# Package indices
inline_macro CtanInlineMacro
inline_macro PypiInlineMacro
inline_macro CratesIOInlineMacro
# App stores
inline_macro FDroidInlineMacro
inline_macro FlathubInlineMacro
# Databases
inline_macro MusicBrainzInlineMacro
inline_macro RepologyInlineMacro
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
module Asciidoctor::Foodogsquared::Extensions
class ChatBlock < Asciidoctor::Extensions::BlockProcessor
use_dsl
named :chat
on_context :example
name_positional_attributes 'avatar', 'state'
default_attributes 'state' => 'default'
def process(parent, _, attrs)
doc_attrs = parent.document.attributes
# Configuring the avatar-related attributes.
attrs['avatarsdir'] ||= doc_attrs['avatarsdir'] || File.expand_path('./avatars', attrs['iconsdir'])
attrs['avatarstype'] ||= doc_attrs['avatarstype'] || 'avif'
attrs['avatarsticker'] = attrs['avatar'].to_kebab
block = create_block parent, :chat, nil, attrs, content_model: :compound
block.add_role 'dialogblock'
block
end
end
end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'open-uri'
require 'yaml'
module Asciidoctor::Foodogsquared::Extensions
class FDroidInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :fdroid
name_positional_attributes 'caption'
default_attributes 'lang' => 'en'
def process(parent, target, attrs)
doc = parent.document
app_id = target
app_metadata_uri = %(https://gitlab.com/fdroid/fdroiddata/-/raw/master/metadata/#{app_id}.yml)
metadata = OpenURI.open_uri(app_metadata_uri) { |f| YAML.safe_load(f.read) }
attrs['caption'] ||= metadata['AutoName']
url = %(https://f-droid.org/#{attrs['lang']}/packages/#{app_id})
doc.register :links, url
create_anchor parent, attrs['caption'], type: :link, target: url
end
end
end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
require 'json'
require 'open-uri'
module Asciidoctor::Foodogsquared::Extensions
class FlathubInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :flathub
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
# FlatHub API seems to have no documentation aside from the source code.
# You can easily infer the API with its source code at
# https://github.com/flathub/website.
app_id = target
app_metadata_uri = %(https://flathub.org/api/v2/appstream/#{app_id})
headers = {
'Accept' => 'application/json',
'User-Agent' => ::Asciidoctor::Foodogsquared::USER_AGENT
}
metadata = OpenURI.open_uri(app_metadata_uri, headers) { |f| JSON.parse(f.read) }
attrs['caption'] ||= metadata['name']
url = %(https://flathub.org/apps/#{app_id})
doc.register :links, url
create_anchor parent, attrs['caption'], type: :link, target: url
end
end
end

View File

@ -0,0 +1,68 @@
# frozen_string_literal: true
require 'rugged'
module Asciidoctor::Foodogsquared::Extensions
class GitBlobIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'git:'
end
def process(doc, reader, target, attrs)
attrs['gitrepo'] ||= doc.attributes['gitrepo'] || doc.base_dir
repo = Rugged::Repository.discover(attrs['gitrepo'])
git_object_ref = target.delete_prefix 'git:'
git_object_ref = doc.attributes['doccontentref'] if git_object_ref.empty?
begin
git_object = repo.rev_parse git_object_ref
if attrs.key? 'diff-option'
options = {}
options[:paths] = attrs['path'].split(';') if attrs.key? 'path'
options[:context_lines] = attrs['context-lines'] if attrs.key? 'context-lines'
options[:reverse] = true if attrs.key? 'reverse-option'
if attrs.key? 'other'
other = repo.rev_parse attrs['other'] || nil
reader.push_include git_object.diff(other, **options).patch
else
reader.push_include git_object.diff(**options).patch
end
else
inner_entry = case git_object.type
when :blob
git_object
when :commit
git_object.tree.path attrs['path']
when :tree
git_object.path attrs['path']
when :tag
git_object.target.tree.path attrs['path']
end
content = repo.lookup(inner_entry[:oid]).content
if attrs.key? 'lines'
content_lines = content.lines
new_content = +''
doc.resolve_lines_to_highlight(content, attrs['lines']).each do |line_no|
new_content << content_lines.at(line_no - 1)
end
content = new_content
end
reader.push_include content
end
rescue StandardError => e
reader.push_include "Unresolved directive for '#{target}' with the following error:\n#{e}"
warn e
end
reader
end
end
end

View File

@ -0,0 +1,70 @@
# frozen_string_literal: true
require 'base64'
require 'json'
require 'open-uri'
require 'uri'
module Asciidoctor::Foodogsquared::Extensions
class GitHubIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'github:'
end
def warn_or_raise(doc, warning)
if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
raise warning
else
warn warning
end
end
def process(doc, reader, target, attrs)
src = target.delete_prefix('github:').split('/', 3)
owner = src.at 0
repo = src.at 1
namespaced_repo = "#{owner}/#{repo}"
path = attrs['path'] || ''
# For more information, see https://docs.github.com/en/rest/repos/contents.
uri = URI.parse %(https://api.github.com/repos/#{owner}/#{repo}/contents/#{path})
if attrs['rev']
query = { ref: attrs['rev'] }
uri.query = URI.encode_www_form query
end
begin
headers = {
'Header' => 'application/vnd.github+json',
'X-GitHub-Api-Version' => '2022-11-28'
}
headers['Authorization'] = "Token #{ENV['GITHUB_API_BEARER_TOKEN']}" if ENV['GITHUB_API_BEARER_TOKEN']
OpenURI.open_uri(uri, headers) do |f|
response = JSON.parse(f.read)
# If the response is an array, it is likely to be a directory. In this
# usecase, we'll just list them.
content = if response.is_a? Array
warning = %(given path '#{path}' from GitHub repo '#{repo}' is a directory)
warn_or_raise doc, warning
warning
elsif response.is_a? Object
Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
end
reader.push_include content, target, target, 1, attrs
end
rescue OpenURI::HTTPError => e
warning = %(error while getting '#{path}' in GitHub repo '#{namespaced_repo}: #{e}')
warn_or_raise doc, warning
reader.push_include warning, target, target, 1, attrs
end
reader
end
end
end

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
require 'uri'
module Asciidoctor::Foodogsquared::Extensions
class GitHubInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :github
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
default_caption = if attrs.key?('repo-option')
target.split('/').at(1)
else
target
end
text = attrs['caption'] || default_caption
uri = URI.parse %(https://github.com/#{target})
if attrs.key? 'issue'
uri.path += %(/issues/#{attrs['issue']})
text << "##{attrs['issue']}" if text == target
else
uri.path += %(/tree/#{attrs['rev']}) if attrs.key? 'rev'
uri.path += %(/#{attrs['path']}) if attrs.key? 'path'
text << "@#{attrs['rev']}" if attrs.key?('rev') && text == target
end
target = uri.to_s
doc.register :links, target
create_anchor parent, text, type: :link, target: target
end
end
end

View File

@ -0,0 +1,60 @@
# frozen_string_literal: true
require 'base64'
require 'json'
require 'open-uri'
require 'uri'
module Asciidoctor::Foodogsquared::Extensions
class GitLabIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'gitlab:'
end
def process(doc, reader, target, attrs)
src = target.delete_prefix('gitlab:').split('/', 2)
owner = src.at 0
repo = src.at 1
namespaced_repo = "#{owner}/#{repo}"
raise %(there is no 'path' attribute given for GitLab repo '#{namespaced_repo}') unless attrs.key? 'path'
raise %(no given ref for getting file in '#{namespaced_repo}') unless attrs.key? 'rev'
path = attrs['path']
rev = attrs['rev']
domain = attrs['domain'] || 'gitlab.com'
version = attrs['version'] || 'v4'
uri = URI.parse %(https://#{domain}/api/#{version})
# Set the project.
uri += %(/projects/#{URI.encode_www_form_component namespaced_repo})
# Then the filename.
uri += %(/repository/files/#{URI.encode_www_form_component path})
# Then the revision.
query = { ref: rev }
uri.query = URI.encode_www_form query
content = begin
headers = { 'Content-Type' => 'application-json' }
header['PRIVATE-TOKEN'] = ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'] if ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN']
OpenURI.open_uri(uri, headers) do |f|
response = JSON.parse(f.read)
Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
end
rescue OpenURI::HTTPError => e
warning = %(error while getting '#{path}' in GitLab repo '#{repo}': #{e})
warn_or_raise doc, warning
warning
end
reader.push_include content, target, target, 1, attrs
reader
end
end
end

View File

@ -0,0 +1,39 @@
# frozen_string_literal: true
require 'uri'
module Asciidoctor::Foodogsquared::Extensions
class GitLabInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :gitlab
name_positional_attributes 'caption'
default_attributes 'domain' => 'gitlab.com'
def process(parent, target, attrs)
doc = parent.document
default_caption = if attrs.key?('repo-option')
target.split('/').at(1)
else
target
end
text = attrs['caption'] || default_caption
uri = URI.parse %(https://#{attrs['domain']}/#{target})
if attrs.key? 'issue'
uri.path += %(/-/issues/#{attrs['issue']})
text << "##{attrs['issue']}" if text == target
else
uri.path += %(/-/tree/#{attrs['rev']}) if attrs.key? 'rev'
uri.path += %(/#{attrs['path']}) if attrs.key? 'path'
text << "@#{attrs['rev']}" if attrs.key?('rev') && text == target
end
target = uri.to_s
doc.register :links, target
create_anchor parent, text, type: :link, target: target
end
end
end

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
module Asciidoctor::Foodogsquared::Extensions
class IETFRFCInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :rfc
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
url = %(https://datatracker.ietf.org/doc/html/#{target})
attrs['caption'] ||= "RFC#{target}"
doc.register :links, url
create_anchor parent, attrs['caption'], type: :link, target: url
end
end
end

View File

@ -0,0 +1,54 @@
# frozen_string_literal: true
module Asciidoctor::Foodogsquared::Extensions
class ManInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :man
name_positional_attributes 'volnum'
default_attributes 'service' => 'debian', 'subpath' => ''
def process(parent, target, attrs)
doc = parent.document
manname = target
text = %(#{manname}(#{attrs['volnum']}))
if doc.basebackend? 'html'
domain = case attrs['service']
when 'debian'
'https://manpages.debian.org'
when 'ubuntu'
'https://manpages.ubuntu.org'
when 'arch'
'https://man.archlinux.org/man'
when 'opensuse'
'https://manpages.opensuse.org'
when 'voidlinux'
'https://man.voidlinux.org'
when 'openbsd'
'https://man.openbsd.org'
when 'none'
nil
else
raise "no available manpage service #{attrs['service']}"
end
subpath = "#{attrs['subpath'].delete_prefix('/').delete_suffix('/')}/" if !attrs['subpath'].empty?
if !domain.nil?
target = %(#{domain}/#{subpath}#{manname}.#{attrs['volnum']})
doc.register :links, target
node = create_anchor parent, text, type: :link, target: target
else
node = create_inline parent, :quoted, text
end
elsif doc.backend == 'manpage'
node = create_inline parent, :quoted, text, type: :strong
else
node = create_inline parent, :quoted, text
end
node
end
end
end

View File

@ -0,0 +1,47 @@
# frozen_string_literal: true
require 'json'
require 'open-uri'
require 'uri'
module Asciidoctor::Foodogsquared::Extensions
class MusicBrainzInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :musicbrainz
name_positional_attributes 'caption', 'type'
default_attributes 'type' => 'release'
def process(parent, target, attrs)
doc = parent.document
root_endpoint = 'https://musicbrainz.org/ws/2'
begin
headers = {
'Accept' => 'application/json',
'User-Agent' => ::Asciidoctor::Foodogsquared::USER_AGENT
}
uri = %(#{root_endpoint}/#{attrs['type']}/#{target})
metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
attrs['caption'] ||= case attrs['type']
when 'artist', 'area', 'events', 'genre', 'instrument', 'label', 'place', 'series'
metadata['name']
when 'recording', 'release-group', 'release', 'cdstub', 'work'
metadata['title']
when 'url'
metadata['resource']
end
target = %(https://musicbrainz.org/#{attrs['type']}/#{target})
doc.register :links, target
create_anchor parent, attrs['caption'], type: :link, target: target
rescue StandardError
warning = %(error while getting Musicbrainz database object '#{target}: #{e}')
warn_or_raise doc, warning
reader.push_include warning, target, target, 1, attrs
end
end
end
end

View File

@ -0,0 +1,58 @@
# frozen_string_literal: true
# I'm fairly sure this could be programmed since Ruby has nice metaprogramming
# capabilities. Though, we'll be keeping it manually defining classes for now
# for initial versions since there could be additional features for each macro.
module Asciidoctor::Foodogsquared::Extensions
class CtanInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :ctan
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://ctan.org/pkg/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end
class PypiInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :pypi
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://pypi.org/project/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end
class CratesIOInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :cratesio
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://crates.io/crates/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end
end

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
module Asciidoctor::Foodogsquared::Extensions
class RepologyInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :repology
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://repology.org/project/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end
end

View File

@ -0,0 +1,55 @@
# frozen_string_literal: true
require 'json'
require 'open-uri'
require 'uri'
module Asciidoctor::Foodogsquared::Extensions
class SWHIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'swh:'
end
def process(doc, reader, target, attributes)
swhid = target
swhid_core_identifier = swhid.split(';').at(0)
swhid_object_type = (swhid_core_identifier.split ':').at 2
unless (doc.safe <= Asciidoctor::SafeMode::SERVER) && (doc.attr? 'allow-uri-read')
raise %('swh:' include cannot be used in safe mode level > SERVER and without attribute 'allow-uri-read')
end
# We're already going to throw out anything that is not content object type
# just to make the later pipelines easier to construct.
if swhid_object_type != 'cnt'
warn %(SWHID '#{swhid_core_identifier}' is not of 'cnt' type; ignoring)
return reader
end
version = '1'
content = begin
uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/resolve/#{target}/)
headers = {
'Accept' => 'application/json'
}
headers['Authorization'] = "Bearer #{ENV['SWH_API_BEARER_TOKEN']}" if ENV['SWH_API_BEARER_TOKEN']
metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
object_hash = metadata['object_id']
uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/content/sha1_git:#{object_hash}/raw/)
OpenURI.open_uri(uri, headers, &:read)
rescue OpenURI::HTTPError => e
warning = %(error while getting '#{swhid_core_identifier}': #{e})
warn warning
warning
end
reader.push_include content, target, target, 1, attributes
reader
end
end
end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Asciidoctor::Foodogsquared::Extensions
class SWHInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :swh
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
# We're only considering `swh:` starting with the scheme version. Also, it
# looks nice aesthetically.
swhid = target.start_with?('swh:') ? target : %(swh:#{target})
default_caption = if attrs.key? 'full-option'
swhid
else
swhid.split(';').at(0)
end
text = attrs['caption'] || default_caption
target = %(https://archive.softwareheritage.org/#{swhid})
doc.register :links, target
create_anchor parent, text, type: :link, target: target
end
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'uri'
module Asciidoctor::Foodogsquared::Extensions
class WikipediaInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :wikipedia
name_positional_attributes 'caption'
default_attributes 'lang' => 'en'
def process(parent, target, attrs)
caption = attrs['caption'] || target
parser = URI::Parser.new
page = parser.escape target
link = %(https://#{attrs['lang']}.wikipedia.org/wiki/#{page})
node = create_anchor parent, caption, type: :link, target: link
create_inline parent, :quoted, node.convert
end
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
class String
def to_kebab
self.gsub(/\s+/, '-') # Replace all spaces with dashes.
.gsub(/[^a-zA-Z0-9-]/, '') # Remove all non-alphanumerical (and dashes) characters.
.gsub(/-+/, '-') # Reduce all dashes into only one.
.gsub(/^-|-+$/, '') # Remove all leading and trailing dashes.
.downcase
end
end
# The namespace for storing Asciidoctor. This is the entry point for the
# entirety of this project.
module Asciidoctor::Foodogsquared
NAME = 'asciidoctor-foodogsquared-custom-extensions'
VERSION = '1.3.0'
CONTACT_EMAIL = 'foodogsquared@foodogsquared.one'
USER_AGENT = "#{NAME}/#{VERSION} ( #{CONTACT_EMAIL} )".freeze
def warn_or_raise(doc, warning)
return raise warning if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
warn warning
end
end

View File

@ -1,68 +0,0 @@
= Git blob include processor
:toc:
An include processor that includes content from the current Git repo.
The use case for this is specifically for creating dedicated branches for certain content.
== Synopsis
[source, asciidoc]
----
include::git:$REVSPEC[]
----
Where `$REVSPEC` is a revision as specified in link:https://manpages.debian.org/gitrevisions.7[gitrevisions.7].
Take note this include processor only accepts a blob object's content to be extracted.
This is meant to be used with other attributes.
See <<Attributes>> for more details.
If the resulting operation ends in an error (i.e., non-existing revision, file, something went wrong), it should log a warning and transclude an error.
== Attributes
- `path` is the filepath to be retrieved from the revision.
When used with `diff`, it changes into a semicolon-delimited (`;`) list of files to make diffs with multiple files.
- `context-lines` is the number of surrounding lines for the diff.
This is only effective if `diff` option is given.
- `other` is the other commit to be compared with.
This is only effective if `diff` option is given.
- `lines` get the specified lines from the path.
It uses the same parser as the line specifier from link:https://docs.asciidoctor.org/asciidoc/latest/verbatim/highlight-lines/[highlighting select lines] so the syntax is the same.
There's also a couple of link:https://docs.asciidoctor.org/asciidoc/latest/attributes/options/[options] for this component.
You can give the following options through `opts` attribute (i.e., `opts="diff,reverse"`).
- `diff` will show the difference in link:https://en.wikipedia.org/wiki/Diff[diff] format.
- `reverse` reverses the sides to be compared.
== Extra notes
The extension is composed of two parts: an include processor and a preprocessor.
The preprocessor add a document attribute, `doccontentref`, which it gives the Git reference for that content.
`doccontentref` is the difference between the process working directory (`Dir.pwd`) and the base directory of the content to be converted.
In case the process working directory is not entirely consistent for several reasons, you could give the attribute `rootdir` as the basis for the comparison.
As another option, you could also manually set `doccontentref` in case it isn't applicable (i.e., for multilingual sites in Hugo projects).
The include processor also accepts an empty target with the prefix (i.e., `include::git:[]`) as a shorthand for `include::git:{doccontentref}`.
== Example usage
The following examples assume that `doccontentref` points to `content/posts/sample`.
- `include::git:HEAD[path=shell.nix]` should transclude the current iteration of `shell.nix`.
- `include::git:{doccontentref}[opts="diff", path=Gemfile]` should include a diff of the Gemfile from `content/posts/sample` branch (assuming that Gemfile has changed).
- `include::git:non-existing-rev[opts="diff"]` should result in a warning with the non-existing revision.
- `include::git:{doccontentref}[path=README, lines=2..5]` should transclude the README file from lines 2-5.

View File

@ -1,79 +0,0 @@
# frozen_string_literal: true
require 'rugged'
class GitBlobIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'git:'
end
def process(doc, reader, target, attrs)
repo = Rugged::Repository.discover(__dir__)
git_object_ref = target.delete_prefix 'git:'
git_object_ref = doc.attributes['doccontentref'] if git_object_ref.empty?
begin
git_object = repo.rev_parse git_object_ref
if attrs.key? 'diff-option'
options = {}
options[:paths] = attrs['path'].split(';') if attrs.key? 'path'
options[:context_lines] = attrs['context-lines'] if attrs.key? 'context-lines'
options[:reverse] = true if attrs.key? 'reverse-option'
if attrs.key? 'other'
other = repo.rev_parse attrs['other'] || nil
reader.push_include git_object.diff(other, **options).patch
else
reader.push_include git_object.diff(**options).patch
end
else
inner_entry = case git_object.type
when :blob
git_object
when :commit
git_object.tree.path attrs['path']
when :tree
git_object.path attrs['path']
when :tag
git_object.target.tree.path attrs['path']
end
content = repo.lookup(inner_entry[:oid]).content
if attrs.key? 'lines'
content_lines = content.lines
new_content = +''
doc.resolve_lines_to_highlight(content, attrs['lines']).each do |line_no|
new_content << content_lines.at(line_no - 1)
end
content = new_content
end
reader.push_include content
end
rescue StandardError => e
reader.push_include "Unresolved directive for '#{target}' with the following error:\n#{e}"
warn e
end
reader
end
end
class GitContentBranchAttributePreprocessor < Asciidoctor::Extensions::Preprocessor
def process(document, reader)
base_dir = Pathname.new(document.base_dir)
rootdir = if document.attributes['rootdir'].nil?
Dir.pwd
else
document.attributes['rootdir']
end
document.attributes['doccontentref'] = base_dir.relative_path_from(rootdir).to_s
reader
end
end

View File

@ -1,49 +0,0 @@
= GitHub link inline macro
:toc:
An inline macro that easily links repositories from GitHub.
== Synopsis
[source, asciidoc]
----
github:$OWNER/$REPO[$CAPTION]
----
If caption is missing, the link text will be the namespace (i.e., `$OWNER/$REPO`) of the repo.
== Attributes
There are optional attributes for this macro.
- `rev` is the commit/branch/tag of the repo to be linked.
When given no caption, it will update the default caption with `$OWNER/$REPO@$REV`.
- `path` is the filepath to be linked within the repo.
- `issue` accepts the issue number to be linked in the GitHub repo.
Take note `issue` is exclusive to other attributes and has more precedence.
For example, if `issue` and `rev` are both present, the link for issue will be the result.
+
When given no caption, it will update the default caption with `$OWNER/$REPO#$ISSUE`.
You can also change certain behaviors with the link:https://docs.asciidoctor.org/asciidoc/latest/attributes/options/[options attribute].
- `repo` sets the default link text with only the repo.
Pretty useful to quickly refer to the name of the software.
== Example usage
- `github:foo-dogsquared/website[]` will link to link:https://github.com/foo-dogsquared/website[my website repository] with the link text `foo-dogsquared/website`.
- `github:NixOS/nixpkgs[nixpkgs nixos-unstable branch, rev=nixos-unstable]` should link to the link:https://github.com/NixOS/nixpkgs/tree/nixos-unstable[NixOS unstable branch of nixpkgs] with a caption of `nixpkgs nixos-unstable branch`.
- `github:errata-ai/vale[Vale v2.3.0 README, path=README.md, rev=v2.3.0]` should link to the link:https://github.com/errata-ai/vale/blob/v2.3.0/README.md[README of Vale v2.3.0].
- `github:neovim/neovim[Neovim cannot open large files properly, issue=614]` should link to https://github.com/neovim/neovim/issues/614[an issue of Neovim] with `Neovim cannot open large files properly` as the link text.
- `github:neovim/neovim[Neovim cannot open large files properly, issue=614, rev=master]` should still link to https://github.com/neovim/neovim/issues/614[an issue of Neovim] since `issue` has more precedence over `rev`.

View File

@ -1,36 +0,0 @@
# frozen_string_literal: true
require 'uri'
class GitHubLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :github
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
default_caption = if attrs.key?('repo-option')
target.split('/').at(1)
else
target
end
text = attrs['caption'] || default_caption
uri = URI.parse %(https://github.com/#{target})
if attrs.key? 'issue'
uri.path += %(/issues/#{attrs['issue']})
text << "##{attrs['issue']}" if text == target
else
uri.path += %(/tree/#{attrs['rev']}) if attrs.key? 'rev'
uri.path += %(/#{attrs['path']}) if attrs.key? 'path'
text << "@#{attrs['rev']}" if attrs.key?('rev') && text == target
end
target = uri.to_s
doc.register :links, target
create_anchor parent, text, type: :link, target: target
end
end

View File

@ -1,40 +0,0 @@
= GitHub raw content include processor
:toc:
This is a link:https://docs.asciidoctor.org/asciidoctor/latest/extensions/include-processor/[include processor] for easily including files from GitHub.
Take note this will only include files.
For directories, submodules, or symlinks: they will not be processed and a warning will be issued.
This extension honors the link:https://docs.asciidoctor.org/asciidoctor/latest/safe-modes/[safe mode setting] and link:https://docs.asciidoctor.org/asciidoc/latest/directives/include-uri/[the prerequisites for permitting includes with URI].
The following is the basic form of using this include processor.
[source, asciidoc]
----
\include::github:$OWNER/$REPO[]
----
== Extra notes
The include processor will use GitHub API.
It can create authorized requests by setting a token in `GITHUB_API_BEARER_TOKEN` environment variable.
For instructions on how to get a token, you can refer to link:https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api?apiVersion=2022-11-28#authenticating[respective documentation].
== Attributes
- `path` for the path of the file to be included.
This is practically required as the root entry of the repository is a directory.
- `rev` is the name of the commit/tag/branch to be checked out.
== Example usage
- `include::github:asciidoctor/asciidoctor[path=README.adoc, rev=v2.0.0]` will include the Asciidoc file from the link:https://github.com/asciidoctor/asciidoctor/[Asciidoctor GitHub repo] from the point of `v2.0.0`.
- `include::github:NixOS/nixpkgs[path=shell.nix]` will get the latest revision of `shell.nix` from link:https://github.com/NixOS/nixpkgs[nixpkgs repository].
- `include::github:foo-dogsquared/nixos-config[]` should not be processed considering it points to the root directory of the repository.

View File

@ -1,68 +0,0 @@
# frozen_string_literal: true
require 'base64'
require 'json'
require 'open-uri'
require 'uri'
class GitHubRawIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'github:'
end
def warn_or_raise(doc, warning)
if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
raise warning
else
warn warning
end
end
def process(doc, reader, target, attrs)
src = target.delete_prefix('github:').split('/', 3)
owner = src.at 0
repo = src.at 1
namespaced_repo = "#{owner}/#{repo}"
path = attrs['path'] || ''
# For more information, see https://docs.github.com/en/rest/repos/contents.
uri = URI.parse %(https://api.github.com/repos/#{owner}/#{repo}/contents/#{path})
if attrs['rev']
query = { ref: attrs['rev'] }
uri.query = URI.encode_www_form query
end
begin
headers = {
'Header' => 'application/vnd.github+json',
'X-GitHub-Api-Version' => '2022-11-28'
}
headers['Authorization'] = "Token #{ENV['GITHUB_API_BEARER_TOKEN']}" if ENV['GITHUB_API_BEARER_TOKEN']
OpenURI.open_uri(uri, headers) do |f|
response = JSON.parse(f.read)
# If the response is an array, it is likely to be a directory. In this
# usecase, we'll just list them.
content = if response.is_a? Array
warning = %(given path '#{path}' from GitHub repo '#{repo}' is a directory)
warn_or_raise doc, warning
warning
elsif response.is_a? Object
Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
end
reader.push_include content, target, target, 1, attrs
end
rescue OpenURI::HTTPError => e
warning = %(error while getting '#{path}' in GitHub repo '#{namespaced_repo}: #{e}')
warn_or_raise doc, warning
reader.push_include warning, target, target, 1, attrs
end
reader
end
end

View File

@ -1,37 +0,0 @@
= GitLab link inline macro
:toc:
An inline macro for easily linking objects from GitLab instances.
== Synopsis
[source, asciidoc]
----
gitlab:$OWNER/$REPO[$CAPTION]
----
== Attributes
- `domain` is the base domain of the GitLab instance.
By default, it points to the official instance of `gitlab.com`.
- `rev` is the commit of the repo.
By default. it doesn't point to anything which should be in the default branch of the repository.
- `path` is the filepath to be linked.
There are settings that is enabled with the link:https://docs.asciidoctor.org/asciidoc/latest/attributes/options/[options attribute].
- `repo` sets the default caption to be the repo part.
== Example usage
- `gitlab:gitlab-org/gitlab[]` will link to link:https://gitlab.com/gitlab-org/gitlab[the GitLab's source code with the default domain].
- `gitlab:gitlab-org/gitlab[rev=0c9f77389424b6c5fd8e96b227e9125a13a07cb3, path=README.md]` should link to the link:https://gitlab.com/gitlab-org/gitlab/-/blob/0c9f77389424b6c5fd8e96b227e9125a13a07cb3/README.md[GitLab's README from 3 years ago].
- `gitlab:GNOME/mutter[domain=gitlab.gnome.org, rev=df653b95adf6462fc731998eb53b0860baa7253c, path=meson.build]` should link to link:https://gitlab.gnome.org/GNOME/mutter/-/blob/df653b95adf6462fc731998eb53b0860baa7253c/meson.build[Mutter v44.beta `meson.build` from GNOME GitLab instance].

View File

@ -1,31 +0,0 @@
# frozen_string_literal: true
require 'uri'
class GitLabLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :gitlab
name_positional_attributes 'caption'
default_attributes 'domain' => 'gitlab.com'
def process(parent, target, attrs)
doc = parent.document
default_caption = if attrs.key?('repo-option')
target.split('/').at(1)
else
target
end
text = attrs['caption'] || default_caption
uri = URI.parse %(https://#{attrs['domain']}/#{target})
uri.path += %(/-/tree/#{attrs['rev']}) if attrs['rev']
uri.path += %(/#{attrs['path']}) if attrs['path']
target = uri.to_s
doc.register :links, target
create_anchor parent, text, type: :link, target: target
end
end

View File

@ -1,44 +0,0 @@
= GitLab raw content include processor
:toc:
It's a link:https://docs.asciidoctor.org/asciidoctor/latest/extensions/include-processor/[include processor] for easily including raw content from GitLab repositories.
== Synopsis
[source, asciidoc]
----
include::gitlab/$OWNER/$REPO[rev=$COMMIT, path=$FILEPATH]
----
== Extra notes
A link:https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#personal-access-tokens[personal access token] is most likely required.
Get one and place the value in an environment variable `GITLAB_API_PERSONAL_ACCESS_TOKEN`.
== Attributes
There are some attributes required to be passed.
- `rev` is the commit to be checked out.
- `path` is the file path to be included.
Aside from the required attributes, there are optional attributes to configured further.
- `domain` is the domain of the GitLab instance.
By default, it points to the `gitlab.com` official instance.
- `version` is the version string of the API to be used.
By default, it uses version `v4`.
== Example usage
- `include::gitlab:gitlab-org/gitlab[rev=master, path=README.md]` should include the README content from the master branch of link:https://gitlab.com/gitlab-org/gitlab/[GitLab source code].
- `include::freedesktop-sdk/freedesktop-sdk[rev=bcb3e0de957519e87a4c7b8c0e40af9876e531e7, path=.gitlab-ci.yml]` should transclude the GitLab CI configuration from link:https://gitlab.com/freedesktop-sdk/freedesktop-sdk[Freedesktop SDK].
- `include::World/warp[domain=gitlab.gnome.org, rev=v0.5.2, path=meson_options.txt]` includes `meson_options.txt` from link:https://gitlab.gnome.org/World/warp/[Warp source code] at v0.5.2.

View File

@ -1,66 +0,0 @@
# frozen_string_literal: true
require 'base64'
require 'json'
require 'open-uri'
require 'uri'
class GitLabRawIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'gitlab:'
end
def warn_or_raise(doc, warning)
if (doc.safe > Asciidoctor::SafeMode::SERVER) && !(doc.attr? 'allow-uri-read')
raise warning
else
warn warning
end
end
def process(doc, reader, target, attrs)
src = target.delete_prefix('gitlab:').split('/', 2)
owner = src.at 0
repo = src.at 1
namespaced_repo = "#{owner}/#{repo}"
raise %(there is no 'path' attribute given for GitLab repo '#{namespaced_repo}') unless attrs.key? 'path'
raise %(no given ref for getting file in '#{namespaced_repo}') unless attrs.key? 'rev'
path = attrs['path']
rev = attrs['rev']
domain = attrs['domain'] || 'gitlab.com'
version = attrs['version'] || 'v4'
uri = URI.parse %(https://#{domain}/api/#{version})
# Set the project.
uri += %(/projects/#{URI.encode_www_form_component namespaced_repo})
# Then the filename.
uri += %(/repository/files/#{URI.encode_www_form_component path})
# Then the revision.
query = { ref: rev }
uri.query = URI.encode_www_form query
content = begin
headers = { 'Content-Type' => 'application-json' }
header['PRIVATE-TOKEN'] = ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'] if ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN']
OpenURI.open_uri(uri, headers) do |f|
response = JSON.parse(f.read)
Base64.decode64 response['content'] if response['content'] && response['encoding'] == 'base64'
end
rescue OpenURI::HTTPError => e
warning = %(error while getting '#{path}' in GitLab repo '#{repo}': #{e})
warn_or_raise doc, warning
warning
end
reader.push_include content, target, target, 1, attrs
reader
end
end

View File

@ -1,20 +0,0 @@
# frozen_string_literal: true
class String
def to_kebab
self.gsub(/\s+/, '-') # Replace all spaces with dashes.
.gsub(/[^a-zA-Z0-9-]/, '') # Remove all non-alphanumerical (and dashes) characters.
.gsub(/-+/, '-') # Reduce all dashes into only one.
.gsub(/^-|-+$/, '') # Remove all leading and trailing dashes.
.downcase
end
end
module Asciidoctor
module FoodogsquaredCustomExtensions
NAME = 'asciidoctor-foodogsquared-custom-extensions'
VERSION = '1.0.0'
CONTACT_EMAIL = 'foodogsquared@foodogsquared.one'
USER_AGENT = "#{NAME}/#{VERSION} ( #{CONTACT_EMAIL} )"
end
end

View File

@ -1,27 +0,0 @@
= Flathub link inline macro
:toc:
A shorthand for linking link:https://datatracker.ietf.org/[IETF RFCs].
== Synopsis
[source, asciidoc]
----
rfc:$RFC[$CAPTION]
----
Where...
- `$RFC` is the RFC number.
- `$CAPTION` is the link text to be used.
By default, it will be `RFC$RFC`.
== Example usage
- `rfc:2136[]` links to the link:https://datatracker.ietf.org/doc/html/rfc2136[RFC2136 (dynamic update)] with the caption `RFC2136`.
- `rfc:2136[Dynamic DNS updates]` is the same as the previous list item but with the caption text `Dynamic DNS updates`.

View File

@ -1,16 +0,0 @@
# frozen_string_literal: true
class IETFRFCLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :rfc
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
url = %(https://datatracker.ietf.org/doc/html/#{target})
attrs['caption'] ||= "RFC#{target}"
doc.register :links, url
create_anchor parent, attrs['caption'], type: :link, target: url
end
end

View File

@ -1,51 +0,0 @@
= Man inline macro
:toc:
It's a link:https://docs.asciidoctor.org/asciidoctorj/latest/extensions/inline-macro-processor/[inline macro] that easily links manual pages from an online manpage service like link:https://manpages.debian.org/[Debian Manpages].
== Synopsis
[source, asciidoc]
----
man:$MANPAGE[$VOLNUM]
----
== Attributes
There are optional attributes that can be passed.
- `volnum` expects the section number where the manual page belongs to.
This attribute is another way to indicate the section in case you start to use more attributes.
The value from `volnum` attribute has higher precedence.
When both the positional argument and `volnum` attribute is passed, the `volnum` attribute will be used.
- `service` is the domain of the online manpage service.
Take note this attribute is only used in `html` backend.
+
--
This is an attribute that expects certain values:
- `debian` uses https://manpages.debian.org.
This is also the default service when no value is given.
- `archlinux` uses https://man.archlinux.org.
- `opensuse` uses https://manpages.opensuse.org.
- `voidlinux` use https://man.voidlinux.org.
- `none` uses none at all. :)
This is useful if the reference is not found anywhere.
Any invalid value raises an error.
--
== Example usage
- `man:crontab[5]` will link to the default manpage service with `crontab(5)` manual page.
- `man:man[volnum=1, service=archlinux]` will link to the link:https://man.archlinux.org/man/man.1[man manpage] from link:https://man.archlinux.org/[man.archlinux.org].

View File

@ -1,45 +0,0 @@
# frozen_string_literal: true
class ManInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :man
name_positional_attributes 'volnum'
default_attributes 'service' => 'debian'
def process(parent, target, attrs)
doc = parent.document
text = manname = target
suffix = (volnum = attrs['volnum']) ? %((#{volnum})) : ''
if doc.basebackend? 'html'
domain = case attrs['service']
when 'debian'
'https://manpages.debian.org'
when 'arch'
'https://man.archlinux.org/man'
when 'opensuse'
'https://manpages.opensuse.org'
when 'voidlinux'
'https://man.voidlinux.org'
when 'none'
nil
else
raise "no available manpage service #{attrs['service']}"
end
if !domain.nil?
target = %(#{domain}/#{manname}.#{volnum})
doc.register :links, target
node = create_anchor parent, text, type: :link, target: target
else
node = create_inline parent, :quoted, manname
end
elsif doc.backend == 'manpage'
node = create_inline parent, :quoted, manname, type: :strong
else
node = create_inline parent, :quoted, manname
end
create_inline parent, :quoted, %(#{node.convert}#{suffix})
end
end

View File

@ -1,45 +0,0 @@
= Musicbrainz link inline macro
:toc:
An inline macro for easily linking objects from link:https://musicbrainz.org/doc/MusicBrainz_Database[Musicbrainz database].
== Synopsis
[source, asciidoc]
----
musicbrainz:$ID[$CAPTION, $TYPE]
----
- `$ID` is the database identifier for that object (e.g., `9adcff14-7dba-4ccf-a6a6-298bcde3dd46`).
- `$CAPTION` is the link text.
By default, it will be the name of the database object (if valid).
Take note it will use the MusicBrainz API to query the title/name of the object.
In other words, it costs an additional network request.
- `$TYPE` is the database object type.
It defaults to 'Release' object type.
== Attributes
The macro can also accept some attributes.
- `caption` is the link text to be used.
This can be used instead of the first positional attribute.
- `type` is the database object type to be queried.
This can be used instead of the second positional attribute.
== Example usage
- `musicbrainz:9adcff14-7dba-4ccf-a6a6-298bcde3dd46[]` should have a link to the link:https://musicbrainz.org/release/9adcff14-7dba-4ccf-a6a6-298bcde3dd46[Musicbrainz page for The Bindings of Isaac Rebirth] with 'The Bindings of Isaac: Rebirth' as the link caption.
- `musicbrainz:9adcff14-7dba-4ccf-a6a6-298bcde3dd46[Ridiculon's Rebirth soundtrack]` same as above but with the link text replaced with 'Ridiculon's Rebirth Soundtrack'.
- `musicbrainz:b7c7f603-4c42-45a4-b364-3ddba82da412[type=release-group]` links to the link:https://musicbrainz.org/release-group/b7c7f603-4c42-45a4-b364-3ddba82da412[Musicbrainz page for The Bindings of Isaac Rebirth release group] with 'The Bindings of Isaac: Rebirth' as the link text.
- `musicbrainz:f07c6afe-ee84-4cd5-9b11-5c541d1dff3b[type=artist]` links to link:https://musicbrainz.org/artist/f07c6afe-ee84-4cd5-9b11-5c541d1dff3b[Musicbrainz page for Ridiculon] with their name as the caption.

View File

@ -1,47 +0,0 @@
# frozen_string_literal: true
require 'json'
require 'open-uri'
require 'uri'
class MusicBrainzLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :musicbrainz
name_positional_attributes 'caption', 'type'
default_attributes 'type' => 'release'
def process(parent, target, attrs)
doc = parent.document
root_endpoint = 'https://musicbrainz.org/ws/2'
begin
headers = {
'Accept' => 'application/json',
'User-Agent' => ::Asciidoctor::FoodogsquaredCustomExtensions::USER_AGENT
}
uri = %(#{root_endpoint}/#{attrs['type']}/#{target})
if attrs['caption'].nil?
metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
attrs['caption'] ||= case attrs['type']
when 'artist', 'area', 'events', 'genre', 'instrument', 'label', 'place', 'series'
metadata['name']
when 'recording', 'release-group', 'release', 'cdstub', 'work'
metadata['title']
when 'url'
metadata['resource']
end
end
target = %(https://musicbrainz.org/#{attrs['type']}/#{target})
doc.register :links, target
create_anchor parent, attrs['caption'], type: :link, target: target
rescue
warning = %(error while getting Musicbrainz database object '#{target}: #{e}')
warn_or_raise doc, warning
reader.push_include warning, target, target, 1, attrs
end
end
end

View File

@ -1,56 +0,0 @@
# frozen_string_literal: true
# I'm fairly sure this could be programmed since Ruby has nice metaprogramming
# capabilities. Though, we'll be keeping it manually defining classes for now
# for initial versions since there could be additional features for each macro.
class CtanLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :ctan
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://ctan.org/pkg/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end
class PypiLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :pypi
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://pypi.org/project/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end
class CratesIOLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :cratesio
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://crates.io/crates/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end

View File

@ -1,27 +0,0 @@
= Repology link inline macro
:toc:
An inline macro for shorthands Repology links.
== Synopsis
[source, asciidoc]
----
repology:$PROJECT[$CAPTION]
----
Where...
- `$PROJECT` is the project name listed in link:https://repology.org/projects/[Repology's project list].
- `$CAPTION` is the link text to be used.
By default, it will use the project name.
== Example usage
- `repology:beets[]` should link to the link:https://repology.org/project/beets/[Beets project page in Repology] with `beets` as the link text.
- `repology:beets[widely available in Linux distributions]` is the same as the previous item but with the link text replaced to `widely available in Linux distributions`.

View File

@ -1,18 +0,0 @@
# frozen_string_literal: true
class RepologyLinkInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :repology
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
text = attrs['caption'] || target
url = %(https://repology.org/project/#{target})
doc.register :links, url
create_anchor parent, text, type: :link, target: url
end
end

View File

@ -1,44 +0,0 @@
= SWHID include processor
:toc:
This is an include processor extension for easily fetching SWHIDs, only with the `cnt` schema type.
== Synopsis
[source, asciidoc]
----
\include::$SWHID[]
----
Where `$SWHID` is a link:https://docs.softwareheritage.org/devel/swh-model/persistent-identifiers.html[SWHID].
This could accept SWHIDs with qualifiers.
Take note this include processor will only give the raw content with the `cnt` schema type.
Anything else will be skipped and log a warning instead.
== Extra notes
[source, asciidoc]
----
= doctitle
:swhid-gpl3: swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2
\include::{swhid-nixpkgs}[]
----
This include processor also respects the safe mode setting.
This means in order to permit including by SWHID, you have to permit link:https://docs.asciidoctor.org/asciidoc/latest/directives/include-uri/[includes by URIs].
Lastly, this include processor uses the Software Heritage API which includes a limitation.
You could create authorized requests by setting `SWH_API_BEARER_TOKEN` environment variable with a token.
== Example usage
- SWHID with a bare core identifier: `include::swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2[]`.
- SWHID with full contextual information: `include::swh:1:cnt:4c6ad635164b25b9bc2ebe17d2c3b7c0835f6035;origin=https://github.com/NixOS/nixpkgs;visit=swh:1:snp:6ea7d28dfd4789609e0be2b64179fc9c12931beb;anchor=swh:1:rev:7f5639fa3b68054ca0b062866dc62b22c3f11505;path=/README.md`.

View File

@ -1,53 +0,0 @@
# frozen_string_literal: true
require 'json'
require 'open-uri'
require 'uri'
class SWHIDIncludeProcessor < Asciidoctor::Extensions::IncludeProcessor
def handles?(target)
target.start_with? 'swh:'
end
def process(doc, reader, target, attributes)
swhid = target
swhid_core_identifier = swhid.split(';').at(0)
swhid_object_type = (swhid_core_identifier.split ':').at 2
unless (doc.safe <= Asciidoctor::SafeMode::SERVER) && (doc.attr? 'allow-uri-read')
raise %('swh:' include cannot be used in safe mode level > SERVER and without attribute 'allow-uri-read')
end
# We're already going to throw out anything that is not content object type
# just to make the later pipelines easier to construct.
if swhid_object_type != 'cnt'
warn %(SWHID '#{swhid_core_identifier}' is not of 'cnt' type; ignoring)
return reader
end
version = '1'
content = begin
uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/resolve/#{target}/)
headers = {
'Accept' => 'application/json'
}
headers['Authorization'] = "Bearer #{ENV['SWH_API_BEARER_TOKEN']}" if ENV['SWH_API_BEARER_TOKEN']
metadata = OpenURI.open_uri(uri, headers) { |f| JSON.parse(f.read) }
object_hash = metadata['object_id']
uri = URI.parse %(https://archive.softwareheritage.org/api/#{version}/content/sha1_git:#{object_hash}/raw/)
OpenURI.open_uri(uri, headers, &:read)
rescue OpenURI::HTTPError => e
warning = %(error while getting '#{swhid_core_identifier}': #{e})
warn warning
warning
end
reader.push_include content, target, target, 1, attributes
reader
end
end

View File

@ -1,54 +0,0 @@
= SWHID inline macro extension
:toc:
An inline macro for easily linking link:https://docs.softwareheritage.org/devel/swh-model/persistent-identifiers.html[SWHIDs].
== Synopsis
[source, asciidoc]
----
swh:$SWHID[$CAPTION]
----
If no caption is given, the link text will be the core identifier of the SWHID.
== Attributes
You can configure certain behavior of the macro with the link:https://docs.asciidoctor.org/asciidoc/latest/attributes/options/[options attribute].
Here's a list of them...
- `full` will make the entire SWHID as the default link text.
== Extra notes
You would use like in the following form `swh:swh:1:snp:6ea7d28dfd4789609e0be2b64179fc9c12931beb[]` but you could also cut off `swh:` from the SWHID if you want to (i.e., `swh:1:snp:6ea7d28dfd4789609e0be2b64179fc9c12931beb[]`) to make it aesthetically pleasing.
Whatever your preference is, the best practice for dealing with linking SWHIDs with this macro is setting attributes containing the SWHIDs.
[source, asciidoc]
----
= doctitle
:swhid-nixpkgs: swh:1:dir:2885ecf76632a83610d8e95f0eb3383109a7c90a
{swhid-nixpkgs}[this revision of nixpkgs]
or
swh:{swhid-nixpkgs}[that revision of nixpkgs]
----
== Example usage
This should work with the following types of SWHIDs.
- A SWHID with only the core identifier: `swh:1:snp:6ea7d28dfd4789609e0be2b64179fc9c12931beb[]`.
- A SWHID with only one qualifier with a link caption: `swh:1:cnt:ce4dd1988d2d5dfcec48252757a6fea94339ac38;lines=3-4[some code text]`
- A SWHID with full contextual information.
This is as depicted from the recommended practice for writings (i.e., blog posts, technical documentation, research papers) when referring to one of the objects in the archive.
+
`swh:1:dir:2885ecf76632a83610d8e95f0eb3383109a7c90a;origin=https://github.com/NixOS/nixpkgs;visit=swh:1:snp:6ea7d28dfd4789609e0be2b64179fc9c12931beb;anchor=swh:1:rev:b7ee21d0ced814d07b7d5aca334dfe018ceafaa5[]`

View File

@ -1,26 +0,0 @@
# frozen_string_literal: true
class SWHInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :swh
name_positional_attributes 'caption'
def process(parent, target, attrs)
doc = parent.document
# We're only considering `swh:` starting with the scheme version. Also, it
# looks nice aesthetically.
swhid = target.start_with?('swh:') ? target : %(swh:#{target})
default_caption = if attrs.key? 'full-option'
swhid
else
swhid.split(';').at(0)
end
text = attrs['caption'] || default_caption
target = %(https://archive.softwareheritage.org/#{swhid})
doc.register :links, target
create_anchor parent, text, type: :link, target: target
end
end

View File

@ -1,30 +0,0 @@
= Wikipedia inline macro
:toc:
An inline macro for easily creating Wikipedia links (i.e., `wikipedia.org`).
== Synopsis
[source, asciidoc]
----
wikipedia:PAGE[$CAPTION]
----
Where if `$CAPTION` is present, it will be used as the link text.
Otherwise, it will just be the page.
== Attributes
- `lang` is the language domain to be linked into.
By default, it is set to `en`.
== Example usage
- `wikipedia:Diff[]` should link to the link:https://en.wikipedia.org/wiki/Diff[Diff page on English Wikipedia].
- `wikipedia:Diff[lang=ja]` should link to the link:https://ja.wikipedia.org/wiki/Diff[Diff page on Japanese Wikipedia].
- `wikipedia:Photosynthesis[lang=simple]` should link to the link:https://simple.wikipedia.org/wiki/Photosynthesis[Photosynthesis page on Simple English Wikipedia].
- `wikipedia:Diff[diff in Japanese Wikipedia, lang=ja]` should link to the link:https://ja.wikipedia.org/wiki/Diff[Diff page on Japanese Wikipedia] with the `diff in Japanese Wikipedia` as the link text.

View File

@ -1,21 +0,0 @@
# frozen_string_literal: true
require 'uri'
class WikipediaInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
use_dsl
named :wikipedia
name_positional_attributes 'caption'
default_attributes 'lang' => 'en'
def process(parent, target, attrs)
caption = attrs['caption'] || target
parser = URI::Parser.new
page = parser.escape target
link = %(https://#{attrs['lang']}.wikipedia.org/wiki/#{page})
node = create_anchor parent, caption, type: :link, target: link
create_inline parent, :quoted, node.convert
end
end

View File

@ -1,27 +1,26 @@
{ pkgs ? import <nixpkgs> { }, ruby-nix }:
{ pkgs ? import <nixpkgs> { }
, extraPackages ? [ ]
, extraBuildInputs ? [ ]
}:
with pkgs;
let
gems = ruby-nix.lib pkgs {
name = "asciidoctor-foodogsquared-extensions";
ruby = ruby_3_1;
gemset = ./gemset.nix;
};
in
mkShell {
buildInputs = [
gems.env
gems.ruby
];
# Dependencies for Nokogiri.
pkg-config
zlib
libiconv
# Dependencies for rugged.
libgit2
] ++ extraBuildInputs;
packages = [
bundix
# Formatters
nixpkgs-fmt
# Language servers
rnix-lsp
];
] ++ extraPackages;
}

View File

@ -0,0 +1,124 @@
# frozen_string_literal: true
describe ChatBlock do
it 'should create a basic chat block' do
input = <<~INPUT
[chat, foodogsquared]
====
Hello there!
====
INPUT
expected = <<~RESULT
<div role="figure" class="dialogblock">
<div class="dialogblock-avatar">
<img src="foodogsquared/default.avif" alt="foodogsquared">
</div>
<div class="dialogblock-text">
<small>foodogsquared</small>
<div class="paragraph">
<p>Hello there!</p>
</div>
</div>
</div>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a basic chat block with non-default values with document attributes' do
input = <<~INPUT
:avatarsdir: /avatars
:avatarstype: webp
[chat, foodogsquared]
====
Hello there!
====
INPUT
expected = <<~RESULT
<div role="figure" class="dialogblock">
<div class="dialogblock-avatar">
<img src="/avatars/foodogsquared/default.webp" alt="foodogsquared">
</div>
<div class="dialogblock-text">
<small>foodogsquared</small>
<div class="paragraph">
<p>Hello there!</p>
</div>
</div>
</div>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a basic chat block with non-default values' do
input = <<~INPUT
:avatarsdir: /avatars
:avatarstype: webp
[chat, foodogsquared, state=nervous, role=shake]
====
Hello there!
*wow*
====
INPUT
expected = <<~RESULT
<div role="figure" class="shake dialogblock">
<div class="dialogblock-avatar">
<img src="/avatars/foodogsquared/nervous.webp" alt="foodogsquared">
</div>
<div class="dialogblock-text">
<small>foodogsquared</small>
<div class="paragraph">
<p>Hello there!</p>
</div>
<div class="paragraph">
<p><strong>wow</strong></p>
</div>
</div>
</div>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a basic chat block with non-default values from the document' do
input = <<~INPUT
[chat, foodogsquared, state=nervous, role=shake]
====
Hello there!
*wow*
====
INPUT
expected = <<~RESULT
<div role="figure" class="shake dialogblock">
<div class="dialogblock-avatar">
<img src="/avatars/foodogsquared/nervous.hello" alt="foodogsquared">
</div>
<div class="dialogblock-text">
<small>foodogsquared</small>
<div class="paragraph">
<p>Hello there!</p>
</div>
<div class="paragraph">
<p><strong>wow</strong></p>
</div>
</div>
</div>
RESULT
attributes = { 'avatarstype' => 'hello', 'avatarsdir' => '/avatars' }
actual = (Asciidoctor.convert input, attributes: attributes).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
end

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
describe FDroidInlineMacro do
it 'should create a FDroid link' do
input = 'fdroid:org.moire.ultrasonic[]'
expected = <<~RESULT
<a href="https://f-droid.org/en/packages/org.moire.ultrasonic">Ultrasonic</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a FDroid link with replaced caption' do
input = 'fdroid:org.moire.ultrasonic[a Subsonic client]'
expected = <<~RESULT
<a href="https://f-droid.org/en/packages/org.moire.ultrasonic">a Subsonic client</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should fail to create a link due to non-existent app' do
input = 'fdroid:com.example.NonExistentAppOrSomething[]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
it 'should fail to create a link due to non-existent app even with replaced caption' do
input = 'fdroid:com.example.NonExistentAppOrSomething[non-existent app]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
end

19
spec/fixtures/HEAD-LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2023 Gabriel Arazas &lt;foodogsquared@foodogsquared.one&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,4 @@
# frozen_string_literal: true
Dir.glob('tasks/*.rake').each {|file| load file }
task default: %w(test:all)

View File

@ -0,0 +1,20 @@
Copyright (c) 2003-2019 Eelco Dolstra and the Nixpkgs/NixOS contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

27
spec/fixtures/v1.0.0-shell.nix vendored Normal file
View File

@ -0,0 +1,27 @@
{ pkgs ? import &lt;nixpkgs&gt; { }, ruby-nix }:
with pkgs;
let
gems = ruby-nix.lib pkgs {
name = "asciidoctor-foodogsquared-extensions";
ruby = ruby_3_1;
gemset = ./gemset.nix;
};
in
mkShell {
buildInputs = [
gems.env
gems.ruby
];
packages = [
bundix
# Formatters
nixpkgs-fmt
# Language servers
rnix-lsp
];
}

View File

@ -0,0 +1,37 @@
# frozen_string_literal: true
describe FlathubInlineMacro do
it 'should create a Flathub link to Icon Library app' do
input = 'flathub:org.gnome.design.IconLibrary[]'
expected = <<~RESULT
<a href="https://flathub.org/apps/org.gnome.design.IconLibrary">Icon Library</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a Flathub link to Icon Library with replaced caption' do
input = 'flathub:org.gnome.design.IconLibrary[GNOME Icon Library]'
expected = <<~RESULT
<a href="https://flathub.org/apps/org.gnome.design.IconLibrary">GNOME Icon Library</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should fail to create a link to Flathub due to non-existent app' do
input = 'flathub:example.com.SomeNonexistentApp[]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
it 'should still fail to link with replaced caption to a non-existent app in Flathub' do
input = 'flathub:example.com.SomeNonexistentApp[replacing the caption]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
end

View File

@ -0,0 +1,63 @@
# frozen_string_literal: true
require 'open-uri'
describe GitBlobIncludeProcessor do
it 'should find the LICENSE from the head commit of this Git repo' do
input = <<~INPUT
[source]
----
include::git:HEAD[path=LICENSE]
----
INPUT
expected = File.read(fixtures_file('HEAD-LICENSE'))
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should find the README from a certain commit' do
input = <<~INPUT
[source]
----
include::git:v1.0.0[path=shell.nix]
----
INPUT
expected = File.read(fixtures_file('v1.0.0-shell.nix'))
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should not find the non-existent commit from this repo' do
input = <<~INPUT
[source]
----
include::git:00000000-0000-0000-0000-000000000000[path=README.adoc]
----
INPUT
expected = <<~RESULT
Unresolved directive for 'git:00000000-0000-0000-0000-000000000000' with the following error:
revspec '00000000-0000-0000-0000-000000000000' not found
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should not find the non-existent repo' do
input = <<~INPUT
:gitrepo: ../very-homeless
[source]
-----
include::git:HEAD[path=README.adoc]
----
INPUT
expect { Asciidoctor.convert input }.to raise_error StandardError
end
end

View File

@ -0,0 +1,108 @@
# frozen_string_literal: true
describe GitHubInlineMacro do
it 'should create a GitHub link with the caption being the target' do
input = <<~INPUT
github:foo-dogsquared/foobarbazxyz[]
INPUT
expected = <<~RESULT
<a href="https://github.com/foo-dogsquared/foobarbazxyz">foo-dogsquared/foobarbazxyz</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a GitHub link to an account' do
input = 'github:foo-dogsquared[]'
expected = <<~RESULT
<a href="https://github.com/foo-dogsquared">foo-dogsquared</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a GitHub link with only the repo as the caption' do
input = 'github:foo-dogsquared/foobarbazxyz[opts=repo]'
expected = <<~RESULT
<a href="https://github.com/foo-dogsquared/foobarbazxyz">foobarbazxyz</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a GitHub link with replaced caption' do
input = 'github:foo-dogsquared/foobarbazxyz[my XYZ project]'
expected = <<~RESULT
<a href="https://github.com/foo-dogsquared/foobarbazxyz">my XYZ project</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a GitHub link to Vale v2.3.0 README' do
input = 'github:errata-ai/vale[path=README.md, rev=v2.3.0]'
expected = <<~RESULT
<a href="https://github.com/errata-ai/vale/tree/v2.3.0/README.md">errata-ai/vale@v2.3.0</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a GitHub link to Vale v2.3.0 README with replaced caption' do
input = 'github:errata-ai/vale[Vale v2.3.0 README, path=README.md, rev=v2.3.0]'
expected = <<~RESULT
<a href="https://github.com/errata-ai/vale/tree/v2.3.0/README.md">Vale v2.3.0 README</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it %(should create a GitHub link to one of Neovim's issues) do
input = 'github:neovim/neovim[issue=614]'
expected = <<~RESULT
<a href="https://github.com/neovim/neovim/issues/614">neovim/neovim#614</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it %(should create a GitHub link to one of Neovim's issues with a replaced caption) do
input = <<~INPUT
github:neovim/neovim[Neovim will not open large files properly, issue=614]
INPUT
expected = <<~RESULT
<a href="https://github.com/neovim/neovim/issues/614">Neovim will not open large files properly</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it %(should still link to one of Neovim's issues) do
input = <<~INPUT
github:neovim/neovim[Neovim will not open large files properly, issue=614, rev=master]
INPUT
expected = <<~RESULT
<a href="https://github.com/neovim/neovim/issues/614">Neovim will not open large files properly</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
end

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
describe GitHubIncludeProcessor do
it 'should include the raw content of a GitHub file successfully' do
input = <<~INPUT
[literal]
....
include::github:asciidoctor/asciidoctor[path=Rakefile, rev=v2.0.0]
....
INPUT
expected = File.read(fixtures_file('asciidoctor-v2.0.0-Rakefile'))
actual = Asciidoctor.convert input.tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should get the raw content of COPYING from nixpkgs at a specific commit' do
commit = 'a46b89df91f56c8aca7de32d270422353d855483'
input = <<~INPUT
[literal]
....
include::github:NixOS/nixpkgs[rev=#{commit}, path=COPYING]
....
INPUT
expected = File.read(fixtures_file("nixpkgs-#{commit}-COPYING"))
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should not process since it points to the root directory of the repo' do
input = 'include::github:asciidoctor/asciidoctor[]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
it 'should fail to point to non-existent repo' do
input = 'include::github:nonexistentrepoyay/OKOKOKOKOKOKOK[path=README.adoc, rev=v2.0.0]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
end

View File

@ -0,0 +1,113 @@
# frozen_string_literal: true
describe GitLabInlineMacro do
it 'should link to the GitLab page for GitLab project' do
input = 'gitlab:gitlab-org/gitlab[]'
expected = <<~RESULT
<a href="https://gitlab.com/gitlab-org/gitlab">gitlab-org/gitlab</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the GitLab page for GitLab project with only the repo part as caption' do
input = 'gitlab:gitlab-org/gitlab[opts=repo]'
expected = <<~RESULT
<a href="https://gitlab.com/gitlab-org/gitlab">gitlab</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the GitLab page for GitLab project with replaced captions' do
input = 'gitlab:gitlab-org/gitlab[GitLab project]'
expected = <<~RESULT
<a href="https://gitlab.com/gitlab-org/gitlab">GitLab project</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the README of the GitLab project in a certain revision' do
input = 'gitlab:gitlab-org/gitlab[rev=0c9f77389424b6c5fd8e96b227e9125a13a07cb3, path=README.md]'
expected = <<~RESULT
<a href="https://gitlab.com/gitlab-org/gitlab/-/tree/0c9f77389424b6c5fd8e96b227e9125a13a07cb3/README.md">gitlab-org/gitlab@0c9f77389424b6c5fd8e96b227e9125a13a07cb3</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the Meson buildspec for GNOME Mutter project on their GitLab instance' do
input = 'gitlab:GNOME/mutter[domain=gitlab.gnome.org, rev=df653b95adf6462fc731998eb53b0860baa7253c, path=meson.build]'
expected = <<~RESULT
<a href="https://gitlab.gnome.org/GNOME/mutter/-/tree/df653b95adf6462fc731998eb53b0860baa7253c/meson.build">GNOME/mutter@df653b95adf6462fc731998eb53b0860baa7253c</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the Meson buildspec for GNOME Mutter project on their GitLab instance with replaced captions' do
input = %(gitlab:GNOME/mutter[Mutter's meson.build, domain=gitlab.gnome.org, rev=df653b95adf6462fc731998eb53b0860baa7253c, path=meson.build])
expected = <<~RESULT
<a href="https://gitlab.gnome.org/GNOME/mutter/-/tree/df653b95adf6462fc731998eb53b0860baa7253c/meson.build">Mutter&#8217;s meson.build</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it %(should link to one of GitLab's issue from the default instance) do
input = 'gitlab:gitlab-org/gitlab[issue=1234]'
expected = <<~RESULT
<a href="https://gitlab.com/gitlab-org/gitlab/-/issues/1234">gitlab-org/gitlab#1234</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it %(should link to one of GNOME Mutter's issue from the GNOME GitLab instance) do
input = 'gitlab:GNOME/mutter[domain=gitlab.gnome.org, issue=1234]'
expected = <<~RESULT
<a href="https://gitlab.gnome.org/GNOME/mutter/-/issues/1234">GNOME/mutter#1234</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it %(should link to one of GNOME Mutter's issue from the GNOME GitLab instance with replaced caption) do
input = %(gitlab:GNOME/mutter[this issue describing Mutter's behavior of resetting scale factor occassionally, domain=gitlab.gnome.org, issue=1234])
expected = <<~RESULT
<a href="https://gitlab.gnome.org/GNOME/mutter/-/issues/1234">this issue describing Mutter&#8217;s behavior of resetting scale factor occassionally</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it %(should still link to issue if both issue and path are given since issues have more precedence) do
input = %(gitlab:GNOME/mutter[path=README.md, domain=gitlab.gnome.org, issue=1234])
expected = <<~RESULT
<a href="https://gitlab.gnome.org/GNOME/mutter/-/issues/1234">GNOME/mutter#1234</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
end

View File

@ -0,0 +1,51 @@
# frozen_string_literal: true
describe GitLabIncludeProcessor, if: ENV['GITLAB_API_PERSONAL_ACCESS_TOKEN'] do
it 'should include the GitLab CI configuration from freedesktop-sdk/freedesktop-sdk from the default instance' do
commit = 'bcb3e0de957519e87a4c7b8c0e40af9876e531e7'
input = <<~INPUT
[literal]
....
include::gitlab:freedesktop-sdk/freedesktop-sdk[rev=#{commit}, path=.gitlab-ci.yml]
....
INPUT
expected = File.read(fixtures_file("freedesktop-sdk-#{commit}-.gitlab-ci.yml"))
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should include the Meson options of Warp from the GNOME GitLab instance' do
commit = 'v0.5.2'
input = <<~INPUT
[literal]
....
include::World/warp[domain=gitlab.gnome.org, rev=#{commit}, path=meson_options.txt]
....
INPUT
expected = File.read(fixtures_file("warp-#{commit}-meson_options.txt"))
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should not process since it points to the root directory of a repo' do
input = 'include::gitlab:freedesktop-sdk/freedesktop-sdk[]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
it 'should fail to point to non-existent repo' do
input = 'include::gitlab:nonexistentrepoyay/OKOKOKOKOKOKOK[path=README.adoc, rev=v2.0.0]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
it 'should fail to point to non-existent repo and a non-existent instance' do
input = 'include::gitlab:nonexistentrepoyay/OKOKOKOKOKOKOK[domain=example.com, path=README.adoc, rev=v2.0.0]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
end

View File

@ -0,0 +1,41 @@
# frozen_string_literal: true
require 'asciidoctor/foodogsquared/converters/html5-extended'
describe Asciidoctor::Foodogsquared::Converters::HTML5Modified do
it 'should have a more semantic version of the admonitions' do
input = <<~INPUT
[WARNING]
====
Hello there
====
INPUT
expected = <<~HTML
<aside data-admonition-type="warning"><div class="admonition-label">Warning</div>
<p>Hello there</p></aside>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have a more semantic version of the admonitions even with typical Asciidoc elements' do
input = <<~INPUT
[#warning-id.big.reversed]
.A warning
[WARNING]
====
Hello there
====
INPUT
expected = <<~HTML
<aside data-admonition-type="warning" id="warning-id" class="big reversed"><div class="admonition-label">Warning</div>
<strong class="title">A warning</strong><p>Hello there</p></aside>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
end

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
require 'asciidoctor/foodogsquared/converters/html5-extended'
describe Asciidoctor::Foodogsquared::Converters::HTML5Modified do
it 'should have an audio block with multiple <source>' do
input = <<~INPUT
audio::hello.mp3[sources="hello.mp3,hello.webm"]
INPUT
expected = <<~HTML
<figure>
<audio><source src="hello.mp3" type="audio/mpeg"><source src="hello.webm" type="audio/webm"><p>Download the audio at <a href="hello.mp3">hello.mp3</a>, <a href="hello.webm">hello.webm</a>.</p></audio>
</figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an audio block with multiple <source> and a caption' do
input = <<~INPUT
.Making up stuff right now
audio::./hello.mp3[sources="hello.mp3,hello.webm"]
INPUT
expected = <<~HTML
<figure>
<audio><source src="hello.mp3" type="audio/mpeg"><source src="hello.webm" type="audio/webm"><p>Download the audio at <a href="hello.mp3">hello.mp3</a>, <a href="hello.webm">hello.webm</a>.</p></audio>
<figcaption>Making up stuff right now</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an audio element with a caption, ID, and classes' do
input = <<~INPUT
[#audio-sample.reverse]
.Making up stuff right now
audio::./hello.mp3[sources="hello.mp3,hello.webm"]
INPUT
expected = <<~HTML
<figure id="audio-sample" class="reverse">
<audio><source src="hello.mp3" type="audio/mpeg"><source src="hello.webm" type="audio/webm"><p>Download the audio at <a href="hello.mp3">hello.mp3</a>, <a href="hello.webm">hello.webm</a>.</p></audio>
<figcaption>Making up stuff right now</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
end

View File

@ -0,0 +1,143 @@
# frozen_string_literal: true
require 'asciidoctor/foodogsquared/converters/html5-extended'
describe Asciidoctor::Foodogsquared::Converters::HTML5Modified do
it 'should have an image block with multiple <source>' do
input = <<~INPUT
image::hello.png[sources="hello.avif,hello.webp"]
INPUT
expected = <<~HTML
<figure>
<picture><source srcset="hello.avif" type="image/avif"><source srcset="hello.webp" type="image/webp"><img src="hello.png" alt="hello"></picture>
</figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an image block with interactive SVG images' do
input = <<~INPUT
image::#{fixtures_file 'hello.svg'}[Interactive, opts=interactive]
INPUT
# rubocop:disable Layout/TrailingWhitespace
expected = <<~HTML
<figure>
<object type="image/svg+xml" data="#{fixtures_file 'hello.svg'}"></object></figure>
HTML
# rubocop:enable Layout/TrailingWhitespace
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an image block with interactive SVG images with a caption' do
input = <<~INPUT
:figure-caption!:
.SVG file
image::#{fixtures_file 'hello.svg'}[Interactive, opts=interactive]
INPUT
# rubocop:disable Layout/TrailingWhitespace
expected = <<~HTML
<figure>
<object type="image/svg+xml" data="#{fixtures_file 'hello.svg'}"></object><figcaption>SVG file</figcaption></figure>
HTML
# rubocop:enable Layout/TrailingWhitespace
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an image block with inline SVG images' do
input = <<~INPUT
image::#{fixtures_file 'hello.svg'}[Inline, opts=inline]
INPUT
expected = <<~HTML
<figure>#{File.read fixtures_file('hello.svg')}
</figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an image block with inline SVG image with a caption' do
input = <<~INPUT
:figure-caption!:
.Inline SVG file
image::#{fixtures_file 'hello.svg'}[Inline, opts=inline]
INPUT
expected = <<~HTML
<figure>#{File.read fixtures_file('hello.svg')}<figcaption>Inline SVG file</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an image block with multiple <source> with caption' do
input = <<~INPUT
:figure-caption!:
.A figure caption
image::hello.png[sources="hello.avif,hello.webp"]
INPUT
expected = <<~HTML
<figure>
<picture><source srcset="hello.avif" type="image/avif"><source srcset="hello.webp" type="image/webp"><img src="hello.png" alt="hello"></picture>
<figcaption>A figure caption</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an image block with multiple <source>, a caption, an ID, and multiple roles' do
input = <<~INPUT
:figure-caption!:
[#image-id.whoa.there]
.A figure caption
image::hello.png[sources="hello.avif,hello.webp"]
INPUT
expected = <<~HTML
<figure id="image-id" class="whoa there">
<picture><source srcset="hello.avif" type="image/avif"><source srcset="hello.webp" type="image/webp"><img src="hello.png" alt="hello"></picture>
<figcaption>A figure caption</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have an image block with multiple <source>, a caption, an ID, and multiple roles with some attributes' do
input = <<~INPUT
:figure-caption!:
[#image-id.whoa.there]
.A figure caption
image::hello.png[sources="hello.avif,hello.webp", width=300, height=100]
INPUT
expected = <<~HTML
<figure id="image-id" class="whoa there">
<picture><source srcset="hello.avif" type="image/avif"><source srcset="hello.webp" type="image/webp"><img width="300" height="100" src="hello.png" alt="hello"></picture>
<figcaption>A figure caption</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
end

View File

@ -0,0 +1,32 @@
# frozen_string_literal: true
require 'asciidoctor/foodogsquared/converters/html5-extended'
describe Asciidoctor::Foodogsquared::Converters::HTML5Modified do
it 'should have a more semantic paragraph output' do
input = <<~INPUT
Hello there, fanciful!
INPUT
expected = <<~HTML
<p>Hello there, fanciful!</p>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should still have a more semantic paragraph output with a title' do
input = <<~INPUT
.Whoa there!
Hello there, fanciful!
INPUT
expected = <<~HTML
<p><strong class="title">Whoa there!</strong>Hello there, fanciful!</p>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
end

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
require 'asciidoctor/foodogsquared/converters/html5-extended'
describe Asciidoctor::Foodogsquared::Converters::HTML5Modified do
it 'should have a more semantic sidebar block' do
input = <<~INPUT
****
A sidebar is used for auxiliary bits of content.
****
INPUT
expected = <<~HTML
<aside><p>A sidebar is used for auxiliary bits of content.</p></aside>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have a more semantic sidebar block with a title' do
input = <<~INPUT
.A sidebar title
****
A sidebar is used for auxiliary bits of content.
****
INPUT
expected = <<~HTML
<aside><strong class="title">A sidebar title</strong><p>A sidebar is used for auxiliary bits of content.</p></aside>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have a more semantic sidebar block with a title, an ID, and several roles' do
input = <<~INPUT
[#sidebar-id.several.roles]
.A sidebar title
****
A sidebar is used for auxiliary bits of content.
****
INPUT
expected = <<~HTML
<aside id="sidebar-id" class="several roles"><strong class="title">A sidebar title</strong><p>A sidebar is used for auxiliary bits of content.</p></aside>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
end

View File

@ -0,0 +1,68 @@
# frozen_string_literal: true
require 'asciidoctor/foodogsquared/converters/html5-extended'
describe Asciidoctor::Foodogsquared::Converters::HTML5Modified do
it 'should have a video block with multiple <source>' do
input = <<~INPUT
video::hello.mp4[sources="hello.mp4,hello.webm"]
INPUT
expected = <<~HTML
<figure>
<video><source src="hello.mp4" type="video/mp4"><source src="hello.webm" type="video/webm"><p>Download the video at <a href="hello.mp4">hello.mp4</a>, <a href="hello.webm">hello.webm</a>.</p></video>
</figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have a video block with a bunch of attributes' do
input = <<~INPUT
video::hello.mp4[opts="autoplay,loop", preload="metadata"]
INPUT
expected = <<~HTML
<figure>
<video autoplay="autoplay" loop="loop" preload="metadata" src="hello.mp4"><p>Download the video at <a href="hello.mp4">hello.mp4</a>.</p></video>
</figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have a video block with multiple <source> and a caption' do
input = <<~INPUT
.Making up stuff right now
video::./hello.mp4[sources="hello.mp4,hello.webm"]
INPUT
expected = <<~HTML
<figure>
<video><source src="hello.mp4" type="video/mp4"><source src="hello.webm" type="video/webm"><p>Download the video at <a href="hello.mp4">hello.mp4</a>, <a href="hello.webm">hello.webm</a>.</p></video>
<figcaption>Making up stuff right now</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
it 'should have a video block with a caption, ID, and classes' do
input = <<~INPUT
[#video-sample.reverse]
.Making up stuff right now
video::./hello.mp4[sources="hello.mp4,hello.webm"]
INPUT
expected = <<~HTML
<figure id="video-sample" class="reverse">
<video><source src="hello.mp4" type="video/mp4"><source src="hello.webm" type="video/webm"><p>Download the video at <a href="hello.mp4">hello.mp4</a>, <a href="hello.webm">hello.webm</a>.</p></video>
<figcaption>Making up stuff right now</figcaption></figure>
HTML
actual = (Asciidoctor.convert input).chomp
(expect actual).to eq expected.chomp
end
end

View File

@ -0,0 +1,51 @@
# frozen_string_literal: true
describe ManInlineMacro do
it 'should process with the default manpage service' do
input = 'man:ls[1]'
expected = <<~RESULT
<a href="https://manpages.debian.org/ls.1">ls(1)</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should process with the Debian Bookworm section' do
input = 'man:ls[1, service=debian, subpath=/bookworm]'
expected = <<~RESULT
<a href="https://manpages.debian.org/bookworm/ls.1">ls(1)</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the Arch Linux manpage' do
input = 'man:ls[volnum=1, service=arch]'
expected = <<~RESULT
<a href="https://man.archlinux.org/man/ls.1">ls(1)</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the empty service' do
input = 'man:ls[volnum=1, service=none]'
expected = '<p>ls(1)</p>'
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected
end
it 'should raise an error from non-existent service type' do
input = 'man:ls[volnum=1, service=manpageservicexyz]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
end

View File

@ -0,0 +1,81 @@
# frozen_string_literal: true
describe MusicBrainzInlineMacro do
it 'should create a MusicBrainz release object with the right captions' do
input = 'musicbrainz:9adcff14-7dba-4ccf-a6a6-298bcde3dd46[]'
expected = <<~RESULT
<a href="https://musicbrainz.org/release/9adcff14-7dba-4ccf-a6a6-298bcde3dd46">The Binding of Isaac: Rebirth</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a MusicBrainz release object with the replaced captions' do
input = 'musicbrainz:9adcff14-7dba-4ccf-a6a6-298bcde3dd46[TBOI Rebirth soundtrack]'
expected = <<~RESULT
<a href="https://musicbrainz.org/release/9adcff14-7dba-4ccf-a6a6-298bcde3dd46">TBOI Rebirth soundtrack</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a MusicBrainz release group object with the right captions' do
input = 'musicbrainz:b7c7f603-4c42-45a4-b364-3ddba82da412[type=release-group]'
expected = <<~RESULT
<a href="https://musicbrainz.org/release-group/b7c7f603-4c42-45a4-b364-3ddba82da412">The Binding of Isaac: Rebirth</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a MusicBrainz release group object with replaced captions' do
input = 'musicbrainz:b7c7f603-4c42-45a4-b364-3ddba82da412[TBOI Rebirth soundtrack, type=release-group]'
expected = <<~RESULT
<a href="https://musicbrainz.org/release-group/b7c7f603-4c42-45a4-b364-3ddba82da412">TBOI Rebirth soundtrack</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a MusicBrainz artist object with right captions' do
input = 'musicbrainz:f07c6afe-ee84-4cd5-9b11-5c541d1dff3b[type=artist]'
expected = <<~RESULT
<a href="https://musicbrainz.org/artist/f07c6afe-ee84-4cd5-9b11-5c541d1dff3b">Ridiculon</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should create a MusicBrainz artist object with replaced captions' do
input = 'musicbrainz:f07c6afe-ee84-4cd5-9b11-5c541d1dff3b[the composer of the TBOI Rebirth soundtrack, type=artist]'
expected = <<~RESULT
<a href="https://musicbrainz.org/artist/f07c6afe-ee84-4cd5-9b11-5c541d1dff3b">the composer of the TBOI Rebirth soundtrack</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should fail to create a MusicBrainz link from non-existent object' do
input = 'musicbrainz:00000000-0000-0000-0000-000000000000[type=artist]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
it 'should fail to create a MusicBrainz link from non-existent object with replaced caption' do
input = 'musicbrainz:00000000-0000-0000-0000-000000000000[what, type=artist]'
expect { Asciidoctor.convert input }.to raise_error StandardError
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
describe RepologyInlineMacro do
it 'should link to the Repology page for beets' do
input = 'repology:beets[]'
expected = <<~RESULT
<a href="https://repology.org/project/beets">beets</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the Repology page for beets with replaced caption' do
input = 'repology:beets[beets is widely available in a lot of the system distributions]'
expected = <<~RESULT
<a href="https://repology.org/project/beets">beets is widely available in a lot of the system distributions</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
end

15
spec/spec_helper.rb Normal file
View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
require 'asciidoctor'
require 'asciidoctor-foodogsquared-extensions'
include Asciidoctor::Foodogsquared::Extensions
RSpec.configure do
def fixtures_dir
File.join __dir__, 'fixtures'
end
def fixtures_file path
File.join fixtures_dir, path
end
end

View File

@ -0,0 +1,55 @@
# frozen_string_literal: true
describe SWHInlineMacro do
it 'should link to the default resolver with the SWHID' do
input = <<~INPUT
swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2[]
INPUT
expected = <<~RESULT
<a href="https://archive.softwareheritage.org/swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2">swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the default resolver with the SWHID but with replaced caption' do
input = <<~INPUT
swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2[GPLv3 license]
INPUT
expected = <<~RESULT
<a href="https://archive.softwareheritage.org/swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2">GPLv3 license</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the default resolver with the SWHID (with one qualifier)' do
input = <<~INPUT
swh:1:cnt:ce4dd1988d2d5dfcec48252757a6fea94339ac38;lines=3-4[]
INPUT
expected = <<~RESULT
<a href="https://archive.softwareheritage.org/swh:1:cnt:ce4dd1988d2d5dfcec48252757a6fea94339ac38;lines=3-4">swh:1:cnt:ce4dd1988d2d5dfcec48252757a6fea94339ac38</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the default resolver with the SWHID (with full recommended qualifiers)' do
input = <<~INPUT
swh:1:dir:2885ecf76632a83610d8e95f0eb3383109a7c90a;origin=https://github.com/NixOS/nixpkgs;visit=swh:1:snp:6ea7d28dfd4789609e0be2b64179fc9c12931beb;anchor=swh:1:rev:b7ee21d0ced814d07b7d5aca334dfe018ceafaa5[]
INPUT
expected = <<~RESULT
<a href="https://archive.softwareheritage.org/swh:1:dir:2885ecf76632a83610d8e95f0eb3383109a7c90a;origin=https://github.com/NixOS/nixpkgs;visit=swh:1:snp:6ea7d28dfd4789609e0be2b64179fc9c12931beb;anchor=swh:1:rev:b7ee21d0ced814d07b7d5aca334dfe018ceafaa5">swh:1:dir:2885ecf76632a83610d8e95f0eb3383109a7c90a</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
end

View File

@ -0,0 +1,47 @@
# frozen_string_literal: true
describe WikipediaInlineMacro do
it 'should link to the Wikipedia page for Diff' do
input = 'wikipedia:Diff[]'
expected = <<~RESULT
<a href="https://en.wikipedia.org/wiki/Diff">Diff</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the Japanese Wikipedia page for Diff' do
input = 'wikipedia:Diff[lang=ja]'
expected = <<~RESULT
<a href="https://ja.wikipedia.org/wiki/Diff">Diff</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the Japanese Wikipedia page for Diff but with replaced captions' do
input = 'wikipedia:Diff[diff in Japanese Wikipedia, lang=ja]'
expected = <<~RESULT
<a href="https://ja.wikipedia.org/wiki/Diff">diff in Japanese Wikipedia</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
it 'should link to the Simple English Wikipedia page for photosynthesis' do
input = 'wikipedia:Photosynthesis[lang=simple]'
expected = <<~RESULT
<a href="https://simple.wikipedia.org/wiki/Photosynthesis">Photosynthesis</a>
RESULT
actual = (Asciidoctor.convert input).tr_s '\n', '\n'
(expect actual).to include expected.chomp
end
end