mirror of
https://github.com/foo-dogsquared/asciidoctor-foodogsquared-extensions.git
synced 2025-04-24 06:19:12 +00:00
Compare commits
66 Commits
Author | SHA1 | Date | |
---|---|---|---|
dd30002f2d | |||
ac2c00567e | |||
6e2c022c45 | |||
bb0e461197 | |||
e0aed2313d | |||
e7e973d1c6 | |||
d868c0964c | |||
09a93481f0 | |||
51d4aa1e99 | |||
d704253410 | |||
a57804d519 | |||
b2d8534999 | |||
36dffaf3e4 | |||
153e110489 | |||
74c48a345f | |||
a6283b72a1 | |||
66233f04e6 | |||
83aad53d74 | |||
887d2a675e | |||
c6f2363ca3 | |||
71fe2602c2 | |||
586cc8daee | |||
5cb366fb2a | |||
f0b69b8af7 | |||
8545b63c84 | |||
e2e0da4a33 | |||
95e7bc12ec | |||
fdcdeb1747 | |||
2977870311 | |||
9d3f69be6e | |||
6291f3b36d | |||
5cd7566a88 | |||
de9f3a0e9c | |||
69c8015292 | |||
2b57ba4594 | |||
850b021209 | |||
a95b09a81f | |||
cf8a942011 | |||
42454be244 | |||
928cd80561 | |||
924fd9eac5 | |||
bfbea57d6b | |||
821d5eeb27 | |||
33faaeac88 | |||
74bb141a79 | |||
60983d0d93 | |||
389abe4176 | |||
e2ca9b57f1 | |||
89c4313d17 | |||
657020278c | |||
1e0fe61e5b | |||
c215300500 | |||
fcb4cb7fde | |||
f385772715 | |||
44a71f5fe3 | |||
ad2834cafe | |||
6e5aa75a6b | |||
de3ced3d3a | |||
2495c6a0ac | |||
fcb06be49f | |||
5ebea76900 | |||
5ec7195fc8 | |||
a28276ae45 | |||
8d59caf6b3 | |||
b052cddf56 | |||
1faf4d45ec |
25
.github/workflows/build.yml
vendored
25
.github/workflows/build.yml
vendored
@ -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
21
.github/workflows/release.yml
vendored
Normal 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
|
14
.rubocop.yml
Normal file
14
.rubocop.yml
Normal 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
|
@ -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
|
||||
|
60
Gemfile.lock
60
Gemfile.lock
@ -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
|
||||
|
@ -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`.
|
||||
|
||||
|
3
Rakefile
3
Rakefile
@ -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
|
||||
|
@ -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
45
flake.lock
generated
@ -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,
|
||||
|
23
flake.nix
23
flake.nix
@ -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;
|
||||
});
|
||||
|
226
gemset.nix
226
gemset.nix
@ -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";
|
||||
};
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'asciidoctor/foodogsquared-extensions'
|
||||
require 'asciidoctor/foodogsquared/extensions'
|
||||
require 'asciidoctor/foodogsquared/converter'
|
||||
|
@ -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__.
|
||||
====
|
||||
....
|
@ -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
|
@ -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].
|
@ -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
|
@ -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`.
|
@ -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
|
@ -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
|
35
lib/asciidoctor/foodogsquared/converter.rb
Normal file
35
lib/asciidoctor/foodogsquared/converter.rb
Normal 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
|
266
lib/asciidoctor/foodogsquared/converters/html5-extended.rb
Normal file
266
lib/asciidoctor/foodogsquared/converters/html5-extended.rb
Normal 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
|
56
lib/asciidoctor/foodogsquared/extensions.rb
Normal file
56
lib/asciidoctor/foodogsquared/extensions.rb
Normal 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
|
26
lib/asciidoctor/foodogsquared/extensions/chat-block.rb
Normal file
26
lib/asciidoctor/foodogsquared/extensions/chat-block.rb
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
54
lib/asciidoctor/foodogsquared/extensions/man-inline-macro.rb
Normal file
54
lib/asciidoctor/foodogsquared/extensions/man-inline-macro.rb
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
26
lib/asciidoctor/foodogsquared/helpers.rb
Normal file
26
lib/asciidoctor/foodogsquared/helpers.rb
Normal 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
|
@ -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.
|
@ -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
|
@ -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`.
|
@ -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
|
@ -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.
|
@ -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
|
@ -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].
|
@ -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
|
@ -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.
|
@ -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
|
@ -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
|
@ -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`.
|
@ -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
|
@ -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].
|
@ -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
|
@ -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.
|
@ -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
|
@ -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
|
@ -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`.
|
@ -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
|
@ -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`.
|
@ -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
|
@ -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[]`
|
@ -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
|
@ -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.
|
@ -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
|
27
shell.nix
27
shell.nix
@ -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;
|
||||
}
|
||||
|
124
spec/chat_block_processor_spec.rb
Normal file
124
spec/chat_block_processor_spec.rb
Normal 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
|
37
spec/fdroid_link_inline_macro_spec.rb
Normal file
37
spec/fdroid_link_inline_macro_spec.rb
Normal 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
19
spec/fixtures/HEAD-LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2023 Gabriel Arazas <foodogsquared@foodogsquared.one>
|
||||
|
||||
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.
|
4
spec/fixtures/asciidoctor-v2.0.0-Rakefile
vendored
Normal file
4
spec/fixtures/asciidoctor-v2.0.0-Rakefile
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
Dir.glob('tasks/*.rake').each {|file| load file }
|
||||
|
||||
task default: %w(test:all)
|
20
spec/fixtures/nixpkgs-a46b89df91f56c8aca7de32d270422353d855483-COPYING
vendored
Normal file
20
spec/fixtures/nixpkgs-a46b89df91f56c8aca7de32d270422353d855483-COPYING
vendored
Normal 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
27
spec/fixtures/v1.0.0-shell.nix
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
{ pkgs ? import <nixpkgs> { }, 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
|
||||
];
|
||||
}
|
37
spec/flathub_link_inline_macro_spec.rb
Normal file
37
spec/flathub_link_inline_macro_spec.rb
Normal 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
|
63
spec/git_blob_include_processor_spec.rb
Normal file
63
spec/git_blob_include_processor_spec.rb
Normal 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
|
108
spec/github_link_inline_macro_spec.rb
Normal file
108
spec/github_link_inline_macro_spec.rb
Normal 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
|
44
spec/github_raw_content_include_processor_spec.rb
Normal file
44
spec/github_raw_content_include_processor_spec.rb
Normal 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
|
113
spec/gitlab_link_inline_macro_spec.rb
Normal file
113
spec/gitlab_link_inline_macro_spec.rb
Normal 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’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’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
|
51
spec/gitlab_raw_content_include_processor_spec.rb
Normal file
51
spec/gitlab_raw_content_include_processor_spec.rb
Normal 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
|
41
spec/html5_modified_converter/admonition.rb
Normal file
41
spec/html5_modified_converter/admonition.rb
Normal 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
|
53
spec/html5_modified_converter/audio.rb
Normal file
53
spec/html5_modified_converter/audio.rb
Normal 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
|
143
spec/html5_modified_converter/image.rb
Normal file
143
spec/html5_modified_converter/image.rb
Normal 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
|
32
spec/html5_modified_converter/paragraph.rb
Normal file
32
spec/html5_modified_converter/paragraph.rb
Normal 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
|
53
spec/html5_modified_converter/sidebar.rb
Normal file
53
spec/html5_modified_converter/sidebar.rb
Normal 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
|
68
spec/html5_modified_converter/video.rb
Normal file
68
spec/html5_modified_converter/video.rb
Normal 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
|
51
spec/man_inline_macro_spec.rb
Normal file
51
spec/man_inline_macro_spec.rb
Normal 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
|
81
spec/musicbrainz_link_inline_macro_spec.rb
Normal file
81
spec/musicbrainz_link_inline_macro_spec.rb
Normal 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
|
25
spec/repology_link_inline_macro_spec.rb
Normal file
25
spec/repology_link_inline_macro_spec.rb
Normal 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
15
spec/spec_helper.rb
Normal 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
|
55
spec/swhid_inline_macro_spec.rb
Normal file
55
spec/swhid_inline_macro_spec.rb
Normal 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
|
47
spec/wikipedia_inline_macro_spec.rb
Normal file
47
spec/wikipedia_inline_macro_spec.rb
Normal 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
|
Loading…
Reference in New Issue
Block a user