newsmlg2 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/docs.yml +63 -0
- data/.github/workflows/links.yml +99 -0
- data/.github/workflows/performance.yml +25 -0
- data/.github/workflows/rake.yml +19 -0
- data/.github/workflows/release.yml +34 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +51 -0
- data/CHANGELOG.md +31 -0
- data/CLAUDE.md +77 -0
- data/Gemfile +15 -0
- data/LICENSE +24 -0
- data/README.adoc +135 -0
- data/Rakefile +15 -0
- data/docs/Gemfile +6 -0
- data/docs/_config.yml +4 -0
- data/docs/index.md +15 -0
- data/docs/lychee.toml +4 -0
- data/docs/usage.md +36 -0
- data/lib/newsmlg2/base/administrative_metadata_group.rb +40 -0
- data/lib/newsmlg2/base/arbitrary_value_attributes.rb +13 -0
- data/lib/newsmlg2/base/authority_attributes.rb +14 -0
- data/lib/newsmlg2/base/common_power_attributes.rb +17 -0
- data/lib/newsmlg2/base/concept_definition_group.rb +25 -0
- data/lib/newsmlg2/base/concept_relationships_group.rb +22 -0
- data/lib/newsmlg2/base/confirmation_status_attributes.rb +13 -0
- data/lib/newsmlg2/base/deprecated_link_attributes.rb +14 -0
- data/lib/newsmlg2/base/descriptive_metadata_group.rb +54 -0
- data/lib/newsmlg2/base/entity_details_group.rb +28 -0
- data/lib/newsmlg2/base/flex_attributes.rb +13 -0
- data/lib/newsmlg2/base/i18n_attributes.rb +14 -0
- data/lib/newsmlg2/base/item_management_group.rb +59 -0
- data/lib/newsmlg2/base/media_content_characteristics1.rb +22 -0
- data/lib/newsmlg2/base/news_content_attributes.rb +18 -0
- data/lib/newsmlg2/base/news_content_characteristics.rb +30 -0
- data/lib/newsmlg2/base/news_content_type_attributes.rb +17 -0
- data/lib/newsmlg2/base/persistent_edit_attributes.rb +13 -0
- data/lib/newsmlg2/base/qualifying_attributes.rb +13 -0
- data/lib/newsmlg2/base/quantify_attributes.rb +13 -0
- data/lib/newsmlg2/base/ranking_attributes.rb +13 -0
- data/lib/newsmlg2/base/recurrence_rule_attributes.rb +18 -0
- data/lib/newsmlg2/base/target_resource_attributes.rb +20 -0
- data/lib/newsmlg2/base/time_validity_attributes.rb +13 -0
- data/lib/newsmlg2/base.rb +35 -0
- data/lib/newsmlg2/builder/node.rb +125 -0
- data/lib/newsmlg2/builder.rb +69 -0
- data/lib/newsmlg2/catalog.rb +38 -0
- data/lib/newsmlg2/catalog_cache.rb +49 -0
- data/lib/newsmlg2/catalog_ref.rb +13 -0
- data/lib/newsmlg2/catalog_store.rb +66 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_32.xml +620 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_33.xml +625 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_34.xml +626 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_35.xml +635 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_36.xml +644 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_37.xml +661 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_38.xml +674 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_39.xml +682 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_40.xml +724 -0
- data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_41.xml +729 -0
- data/lib/newsmlg2/configuration.rb +61 -0
- data/lib/newsmlg2/document.rb +123 -0
- data/lib/newsmlg2/errors.rb +18 -0
- data/lib/newsmlg2/i18n.rb +20 -0
- data/lib/newsmlg2/items/any_item.rb +180 -0
- data/lib/newsmlg2/items/catalog_item.rb +24 -0
- data/lib/newsmlg2/items/concept_item.rb +23 -0
- data/lib/newsmlg2/items/content_meta.rb +73 -0
- data/lib/newsmlg2/items/item_ref.rb +13 -0
- data/lib/newsmlg2/items/knowledge_item.rb +68 -0
- data/lib/newsmlg2/items/news_item.rb +130 -0
- data/lib/newsmlg2/items/news_message.rb +142 -0
- data/lib/newsmlg2/items/package_item.rb +82 -0
- data/lib/newsmlg2/items/part_meta.rb +68 -0
- data/lib/newsmlg2/items/planning_item.rb +160 -0
- data/lib/newsmlg2/nar_model.rb +76 -0
- data/lib/newsmlg2/nar_namespace.rb +10 -0
- data/lib/newsmlg2/nitf_namespace.rb +9 -0
- data/lib/newsmlg2/same_as_scheme.rb +15 -0
- data/lib/newsmlg2/scheme.rb +30 -0
- data/lib/newsmlg2/types/approximate_date_time_prop_type.rb +14 -0
- data/lib/newsmlg2/types/bag.rb +16 -0
- data/lib/newsmlg2/types/block_types.rb +62 -0
- data/lib/newsmlg2/types/concept.rb +36 -0
- data/lib/newsmlg2/types/concept_id.rb +17 -0
- data/lib/newsmlg2/types/concept_name_type.rb +17 -0
- data/lib/newsmlg2/types/content_meta_types.rb +152 -0
- data/lib/newsmlg2/types/date_opt_time_prop_type.rb +12 -0
- data/lib/newsmlg2/types/date_time_or_null_prop_type.rb +12 -0
- data/lib/newsmlg2/types/date_time_prop_type.rb +12 -0
- data/lib/newsmlg2/types/event_details.rb +213 -0
- data/lib/newsmlg2/types/ext_property.rb +21 -0
- data/lib/newsmlg2/types/facet.rb +17 -0
- data/lib/newsmlg2/types/flex1_prop_type.rb +32 -0
- data/lib/newsmlg2/types/flex_location_prop_type.rb +43 -0
- data/lib/newsmlg2/types/flex_party_prop_type.rb +49 -0
- data/lib/newsmlg2/types/flex_prop2_type.rb +26 -0
- data/lib/newsmlg2/types/flex_prop_type.rb +17 -0
- data/lib/newsmlg2/types/geo.rb +92 -0
- data/lib/newsmlg2/types/hierarchy_info.rb +17 -0
- data/lib/newsmlg2/types/ids.rb +28 -0
- data/lib/newsmlg2/types/inline_types.rb +56 -0
- data/lib/newsmlg2/types/intl_string_type.rb +17 -0
- data/lib/newsmlg2/types/intl_string_type2.rb +14 -0
- data/lib/newsmlg2/types/item_management.rb +74 -0
- data/lib/newsmlg2/types/link.rb +40 -0
- data/lib/newsmlg2/types/object_details.rb +40 -0
- data/lib/newsmlg2/types/party_details.rb +258 -0
- data/lib/newsmlg2/types/poi.rb +79 -0
- data/lib/newsmlg2/types/qcode_prop_type.rb +12 -0
- data/lib/newsmlg2/types/qual_prop_type.rb +23 -0
- data/lib/newsmlg2/types/qual_rel_prop_type.rb +18 -0
- data/lib/newsmlg2/types/related_concept.rb +71 -0
- data/lib/newsmlg2/types/rights.rb +84 -0
- data/lib/newsmlg2/types/ruby_annotation.rb +55 -0
- data/lib/newsmlg2/types/same_as.rb +17 -0
- data/lib/newsmlg2/types/truncated_date_time_prop_type.rb +13 -0
- data/lib/newsmlg2/types/versioned_string_type.rb +10 -0
- data/lib/newsmlg2/types/xml_base.rb +12 -0
- data/lib/newsmlg2/types/xml_lang.rb +12 -0
- data/lib/newsmlg2/types.rb +166 -0
- data/lib/newsmlg2/utils.rb +42 -0
- data/lib/newsmlg2/version.rb +5 -0
- data/lib/newsmlg2.rb +181 -0
- data/lib/tasks/performance.rake +72 -0
- data/newsmlg2.gemspec +34 -0
- metadata +185 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 556c768538613353dfff0fcadf54e6b11a810d7aa6fce89b1182204d6135f471
|
|
4
|
+
data.tar.gz: f8a212eb59e47d8e0118e54472d03589fb6f471df17750d686a258576f1b86e1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2df4c64419fce1237b3a91228b9bf04f8b8cc612fcee7c3d97a445370ce9287eb00b59f069df15a7eca02940b2bc9b60ff1afaae0038b5b3f258daab8329232a
|
|
7
|
+
data.tar.gz: d02c09c2b4c808bb5bc62769f7a9471da7ef2316a0544f3ed392b2babbd65007453dbefab2934c7eeb132b00eb47350e055696450892ea159e620e3591edcee6
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- 'docs/**'
|
|
8
|
+
pull_request:
|
|
9
|
+
paths:
|
|
10
|
+
- 'docs/**'
|
|
11
|
+
repository_dispatch:
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
pages: write
|
|
17
|
+
id-token: write
|
|
18
|
+
|
|
19
|
+
concurrency:
|
|
20
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
21
|
+
cancel-in-progress: false
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
build:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@v6
|
|
29
|
+
|
|
30
|
+
- name: Setup Ruby
|
|
31
|
+
uses: ruby/setup-ruby@v1
|
|
32
|
+
with:
|
|
33
|
+
ruby-version: '3.3'
|
|
34
|
+
bundler-cache: true
|
|
35
|
+
cache-version: 0
|
|
36
|
+
working-directory: docs
|
|
37
|
+
|
|
38
|
+
- name: Setup Pages
|
|
39
|
+
id: pages
|
|
40
|
+
uses: actions/configure-pages@v5
|
|
41
|
+
|
|
42
|
+
- name: Build with Jekyll
|
|
43
|
+
run: bundle exec jekyll build --verbose --trace --baseurl "${{ steps.pages.outputs.base_path }}"
|
|
44
|
+
working-directory: docs
|
|
45
|
+
env:
|
|
46
|
+
JEKYLL_ENV: production
|
|
47
|
+
|
|
48
|
+
- name: Upload artifact
|
|
49
|
+
uses: actions/upload-pages-artifact@v4
|
|
50
|
+
with:
|
|
51
|
+
path: docs/_site
|
|
52
|
+
|
|
53
|
+
deploy:
|
|
54
|
+
environment:
|
|
55
|
+
name: github-pages
|
|
56
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
57
|
+
if: ${{ github.ref == 'refs/heads/main' }}
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
needs: build
|
|
60
|
+
steps:
|
|
61
|
+
- name: Deploy to GitHub Pages
|
|
62
|
+
id: deployment
|
|
63
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
name: links
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
paths:
|
|
8
|
+
- 'docs/**'
|
|
9
|
+
pull_request:
|
|
10
|
+
paths:
|
|
11
|
+
- 'docs/**'
|
|
12
|
+
|
|
13
|
+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
pull-requests: write
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
link_checker:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
|
+
|
|
24
|
+
- uses: ruby/setup-ruby@v1
|
|
25
|
+
with:
|
|
26
|
+
ruby-version: '3.4'
|
|
27
|
+
bundler-cache: true
|
|
28
|
+
working-directory: docs
|
|
29
|
+
|
|
30
|
+
- name: Build site
|
|
31
|
+
env:
|
|
32
|
+
JEKYLL_ENV: production
|
|
33
|
+
run: bundle exec jekyll build --trace
|
|
34
|
+
working-directory: docs
|
|
35
|
+
|
|
36
|
+
- name: Restore lychee cache
|
|
37
|
+
uses: actions/cache@v4
|
|
38
|
+
with:
|
|
39
|
+
path: .lycheecache
|
|
40
|
+
key: cache-lychee-${{ github.sha }}
|
|
41
|
+
restore-keys: cache-lychee-
|
|
42
|
+
|
|
43
|
+
- name: Check if site was built
|
|
44
|
+
run: |
|
|
45
|
+
if [ ! -d "_site" ]; then
|
|
46
|
+
echo "Error: _site directory not created"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
echo "Site built successfully"
|
|
50
|
+
ls -la _site/
|
|
51
|
+
working-directory: docs
|
|
52
|
+
|
|
53
|
+
- name: Link Checker (Built Site)
|
|
54
|
+
uses: lycheeverse/lychee-action@v2
|
|
55
|
+
with:
|
|
56
|
+
# Check the built HTML site for rendered links
|
|
57
|
+
# Only check https and http schemes, exclude file:// due to path resolution issues
|
|
58
|
+
args: >-
|
|
59
|
+
--verbose
|
|
60
|
+
--no-progress
|
|
61
|
+
--config lychee.toml
|
|
62
|
+
--root-dir "$(pwd)/_site"
|
|
63
|
+
--scheme https,http
|
|
64
|
+
'_site/**/*.html'
|
|
65
|
+
fail: true
|
|
66
|
+
output: link-check-results.md
|
|
67
|
+
format: markdown
|
|
68
|
+
workingDirectory: docs
|
|
69
|
+
|
|
70
|
+
- name: Upload link check results
|
|
71
|
+
if: always()
|
|
72
|
+
uses: actions/upload-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
name: link-check-results
|
|
75
|
+
path: |
|
|
76
|
+
docs/link-check-results.md
|
|
77
|
+
retention-days: 30
|
|
78
|
+
|
|
79
|
+
- name: Comment PR with results
|
|
80
|
+
if: failure() && github.event_name == 'pull_request'
|
|
81
|
+
uses: actions/github-script@v7
|
|
82
|
+
with:
|
|
83
|
+
script: |
|
|
84
|
+
const fs = require('fs');
|
|
85
|
+
let comment = '## 🔗 Link Check Failed\n\n';
|
|
86
|
+
|
|
87
|
+
if (fs.existsSync('docs/link-check-results.md')) {
|
|
88
|
+
const results = fs.readFileSync('docs/link-check-results.md', 'utf8');
|
|
89
|
+
comment += '### Built Site Results\n\n' + results + '\n\n';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
comment += '\n---\n\n*Please fix the broken links and push a new commit.*';
|
|
93
|
+
|
|
94
|
+
github.rest.issues.createComment({
|
|
95
|
+
issue_number: context.issue.number,
|
|
96
|
+
owner: context.repo.owner,
|
|
97
|
+
repo: context.repo.repo,
|
|
98
|
+
body: comment
|
|
99
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: performance
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
performance:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 15
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
|
|
18
|
+
- name: Set up Ruby
|
|
19
|
+
uses: ruby/setup-ruby@v1
|
|
20
|
+
with:
|
|
21
|
+
ruby-version: 3.4
|
|
22
|
+
bundler-cache: true
|
|
23
|
+
|
|
24
|
+
- name: Run performance benchmarks
|
|
25
|
+
run: bundle exec rake performance:compare
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
|
2
|
+
# See https://github.com/metanorma/cimas
|
|
3
|
+
name: rake
|
|
4
|
+
|
|
5
|
+
permissions:
|
|
6
|
+
contents: write
|
|
7
|
+
packages: write
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [ master, main ]
|
|
12
|
+
tags: [ v* ]
|
|
13
|
+
pull_request:
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
rake:
|
|
17
|
+
uses: metanorma/ci/.github/workflows/generic-rake.yml@main
|
|
18
|
+
secrets:
|
|
19
|
+
pat_token: ${{ secrets.LUTAML_CI_PAT_TOKEN }}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
|
2
|
+
# See https://github.com/metanorma/cimas
|
|
3
|
+
name: release
|
|
4
|
+
|
|
5
|
+
permissions:
|
|
6
|
+
contents: write
|
|
7
|
+
packages: write
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
inputs:
|
|
13
|
+
next_version:
|
|
14
|
+
description: |
|
|
15
|
+
Next release version. Possible values: x.y.z, major, minor, patch (or pre|rc|etc).
|
|
16
|
+
Also, you can pass 'skip' to skip 'git tag' and do 'gem push' for the current version
|
|
17
|
+
required: true
|
|
18
|
+
default: 'skip'
|
|
19
|
+
acknowledge_breaking_in_patch:
|
|
20
|
+
description: 'Override the patch-release breaking-change guard when the trip is a known false-positive'
|
|
21
|
+
required: false
|
|
22
|
+
type: boolean
|
|
23
|
+
default: false
|
|
24
|
+
repository_dispatch:
|
|
25
|
+
types: [ do-release ]
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
release:
|
|
29
|
+
uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
|
|
30
|
+
with:
|
|
31
|
+
next_version: ${{ github.event.inputs.next_version }}
|
|
32
|
+
acknowledge_breaking_in_patch: ${{ inputs.acknowledge_breaking_in_patch }}
|
|
33
|
+
secrets:
|
|
34
|
+
rubygems-api-key: ${{ secrets.LUTAML_CI_RUBYGEMS_API_KEY }}
|
data/.gitignore
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/.bundle/
|
|
2
|
+
/.yardoc
|
|
3
|
+
/Gemfile.lock
|
|
4
|
+
/_yardoc
|
|
5
|
+
/coverage/
|
|
6
|
+
/doc/
|
|
7
|
+
/pkg/
|
|
8
|
+
/spec/reports/
|
|
9
|
+
/spec/examples.txt
|
|
10
|
+
/tmp/
|
|
11
|
+
.rspec_status
|
|
12
|
+
/docs/_site/
|
|
13
|
+
/docs/.jekyll-cache/
|
|
14
|
+
/docs/.jekyll-metadata
|
|
15
|
+
/docs/Gemfile.lock
|
|
16
|
+
/docs/vendor/
|
|
17
|
+
/TODO.impl/
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- rubocop
|
|
3
|
+
|
|
4
|
+
AllCops:
|
|
5
|
+
NewCops: enable
|
|
6
|
+
TargetRubyVersion: 3.3
|
|
7
|
+
Exclude:
|
|
8
|
+
- "pkg/**/*"
|
|
9
|
+
- "vendor/**/*"
|
|
10
|
+
- "coverage/**/*"
|
|
11
|
+
- "reference-docs/**/*"
|
|
12
|
+
- "spec/fixtures/**/*"
|
|
13
|
+
- "data/**/*"
|
|
14
|
+
|
|
15
|
+
Metrics/BlockLength:
|
|
16
|
+
Exclude:
|
|
17
|
+
- "spec/**/*"
|
|
18
|
+
- "*.gemspec"
|
|
19
|
+
- "lib/newsmlg2/base/**/*"
|
|
20
|
+
- "lib/tasks/*.rake"
|
|
21
|
+
|
|
22
|
+
Metrics/MethodLength:
|
|
23
|
+
Exclude:
|
|
24
|
+
- "lib/newsmlg2/base/**/*"
|
|
25
|
+
- "lib/newsmlg2/builder/**/*"
|
|
26
|
+
|
|
27
|
+
Metrics/AbcSize:
|
|
28
|
+
Exclude:
|
|
29
|
+
- "lib/newsmlg2/base/**/*"
|
|
30
|
+
- "lib/newsmlg2/builder/**/*"
|
|
31
|
+
|
|
32
|
+
Metrics/ModuleLength:
|
|
33
|
+
Exclude:
|
|
34
|
+
- "lib/newsmlg2/base/**/*"
|
|
35
|
+
- "lib/newsmlg2.rb"
|
|
36
|
+
- "lib/newsmlg2/types.rb"
|
|
37
|
+
- "lib/newsmlg2/base.rb"
|
|
38
|
+
- "spec/support/**/*"
|
|
39
|
+
|
|
40
|
+
Layout/LineLength:
|
|
41
|
+
Exclude:
|
|
42
|
+
- "lib/newsmlg2/base/**/*"
|
|
43
|
+
- "spec/**/*"
|
|
44
|
+
|
|
45
|
+
Lint/ConstantDefinitionInBlock:
|
|
46
|
+
Exclude:
|
|
47
|
+
- "spec/**/*"
|
|
48
|
+
- "lib/tasks/*.rake"
|
|
49
|
+
|
|
50
|
+
Style/Documentation:
|
|
51
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
|
|
7
|
+
## [0.1.1] - 2026-08-30
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `Newsmlg2.parse` now works on a fresh install with no XML adapter
|
|
12
|
+
configured: when the configured adapter cannot be resolved, the
|
|
13
|
+
stdlib REXML adapter is used instead of raising.
|
|
14
|
+
- Renamed `InlineData#encoding` to `#content_encoding` (wire name
|
|
15
|
+
unchanged) to silence a lutaml-model override warning at load time.
|
|
16
|
+
|
|
17
|
+
## [0.1.0] - 2026-08-30
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Initial release: a lutaml-model-based Ruby object model for IPTC
|
|
22
|
+
NewsML-G2 (NAR) targeting specification version 2.35 (power conformance).
|
|
23
|
+
- Typed parsing and serialization of all seven item types plus
|
|
24
|
+
`newsMessage`, with per-document catalog stores and bundled IPTC
|
|
25
|
+
catalogs (v32–v41) for offline qcode ⇄ URI resolution.
|
|
26
|
+
- Reflection-driven builder DSL (`Newsmlg2.build_news_item`, …) generated
|
|
27
|
+
from the model metadata.
|
|
28
|
+
- Full port of the python-newsmlg2 test suite.
|
|
29
|
+
- Compliance fixtures: the 35 official IPTC example documents and the
|
|
30
|
+
official IPTC XSD validation unit-test suite (161 files across schema
|
|
31
|
+
versions 2.9–2.35).
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project
|
|
6
|
+
|
|
7
|
+
`newsmlg2` — a lutaml-model-based Ruby object model for IPTC **NewsML-G2** (News Architecture, NAR): parse, manipulate, build (DSL), and serialize NewsML-G2 XML with round-trip fidelity. Targets spec version **2.35**, **power** conformance. Namespace: `Newsmlg2`.
|
|
8
|
+
|
|
9
|
+
Implementation was driven by the ordered plan files in **`TODO.impl/`** (`01-…` through `14-…`; kept locally only — the directory is gitignored). Their completion records document every port deviation and design decision.
|
|
10
|
+
|
|
11
|
+
## Reference codebases — READ, do not guess
|
|
12
|
+
|
|
13
|
+
Four local checkouts are the authority for this port. Consult them before designing anything:
|
|
14
|
+
|
|
15
|
+
| Path | Role |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `/Users/mulgogi/src/external/python-newsmlg2/` | Reference implementation (Python, lxml). ~317 model classes in `NewsMLG2/*.py`; its `tests/` (11 files, 35 tests, 13 fixtures in `tests/test_files/`) must be **ported fully and pass**. |
|
|
18
|
+
| `/Users/mulgogi/src/external/newsml-g2/` | **Official IPTC spec repo** (git@github.com:iptc/newsml-g2). XSDs in `specification/` and `tests/schema_versions/`; 31 example listings in `examples/`; official unit-test suite: 161 XML files in `tests/unit_test_files/{version}/should_pass|should_fail/` run by `tests/runtests.py`. All are compliance fixtures for our specs. |
|
|
19
|
+
| `/Users/mulgogi/src/lutaml/chemicalml/` | Sibling gem whose **gemspec, GitHub workflows, and architecture we fully adopt** (gemspec, `.github/workflows/rake.yml`+`release.yml`, `Base::*` mixin pattern, canon-based round-trip specs). |
|
|
20
|
+
| `/Users/mulgogi/src/plurimath/mml/` | **Registry-pattern reference**: how models register into a lutaml GlobalContext (`register_model(Klass, id:)`), resolve via `GlobalContext.resolve_type`, and model heterogeneous children with per-element attributes + symbol types (CommonElements). |
|
|
21
|
+
| `/Users/mulgogi/src/mn/metanorma-document/` | lutaml-model usage reference. NOTE: it has **no builder DSL** — the NewsML builder DSL is generated generically from model metadata. |
|
|
22
|
+
| `/Users/mulgogi/src/lutaml/lutaml-model/docs/` | lutaml-model's own documentation (guides/references/tutorials) — the authority on the framework's public API. |
|
|
23
|
+
|
|
24
|
+
Ground truth on NewsML-G2 semantics (item types, itemMeta/contentMeta/partMeta, catalog/scheme/qcode system, conformance levels): the 2.35 XSDs in the official repo (`specification/individual/NewsML-G2_2.35-spec-Framework-Power.xsd` is the core, 5.3k lines).
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
bundle install # deps: lutaml-model ~> 0.8, dev: rspec, rubocop, nokogiri, canon, simplecov
|
|
30
|
+
bundle exec rake # default task = rspec
|
|
31
|
+
bundle exec rspec # full suite
|
|
32
|
+
bundle exec rspec spec/newsmlg2/catalog_spec.rb # one file
|
|
33
|
+
bundle exec rspec spec/newsmlg2/catalog_spec.rb:42 # one example by line
|
|
34
|
+
bundle exec rspec -e "round trips" # by description
|
|
35
|
+
bundle exec rubocop # lint (TargetRubyVersion 3.3, NewCops: enable)
|
|
36
|
+
bundle exec rubocop -a # safe autocorrect
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
RSpec config lives in `spec/spec_helper.rb` (no `.rspec` file): nokogiri XML adapter, canon semantic-XML comparison (`be_xml_equivalent_to`, wrap compared docs in `<r>…</r>`), random order, focus filtering.
|
|
40
|
+
|
|
41
|
+
Never modify vendored fixture files under `spec/fixtures/` (copied from the reference repos); regenerate/copy anew if needed.
|
|
42
|
+
|
|
43
|
+
## Architecture
|
|
44
|
+
|
|
45
|
+
### Model layer (chemicalml pattern)
|
|
46
|
+
|
|
47
|
+
One Ruby class per NewsML-G2 complex type, `snake_case` file per class under `lib/newsmlg2/`, all wired with `autoload` from `lib/newsmlg2.rb` (never `require_relative`).
|
|
48
|
+
|
|
49
|
+
- **`Base::*` modules** (`lib/newsmlg2/base/`) — one per XSD *attribute group* (`CommonPowerAttributes`, `I18NAttributes`, `FlexAttributes`, …) and per shared *element group* (`ItemManagementGroup`, `DescriptiveMetadataGroup`, `ConceptRelationshipsGroup`, …). Each declares its `attribute`s and appends mappings via a `self.included(klass)` hook — this is how python-newsmlg2's multiple-inheritance MRO merging translates to Ruby mixins.
|
|
50
|
+
- **Wire classes** — thin: `class NewsItem < Lutaml::Model::Serializable; include Base::…; include …; end` with their `xml do … end` mapping (`root`, `map_element`, `map_attribute`, `map_content`).
|
|
51
|
+
- **Namespaces** — `Newsmlg2::NarNamespace` (`http://iptc.org/std/nar/2006-10-01/`, default/unprefixed) and `Newsmlg2::NitfNamespace`; `xml:lang`/`xml:base` attributes come from `Lutaml::Xml::W3c::XmlNamespace`. Set via `namespace` in the `xml` block.
|
|
52
|
+
- **xs:any / unknown children** — captured with `map_all` (raw round-trip), replacing python-newsmlg2's `ExtensionElement`/`_xs_any_content`.
|
|
53
|
+
- All serialization goes through lutaml-model mappings. **Never** hand-roll `to_h`/`from_h`/`to_xml` on model classes.
|
|
54
|
+
|
|
55
|
+
### Subsystems
|
|
56
|
+
|
|
57
|
+
- **`Newsmlg2::Configuration`** — the registry: every root model is registered by element id (`register_model(NewsItem, id: :"newsItem")` … in the `lib/newsmlg2.rb` module body) into a lutaml GlobalContext. It is the **single source of truth** for element-name → class resolution.
|
|
58
|
+
- **`Newsmlg2::Document`** — thin entry point: `Newsmlg2.parse(xml)` / `parse_file(path)` resolves the root class **through the registry** and delegates to `klass.from_xml`; `#item`/`#item=`; `#to_xml` with declaration; writes required defaults (`standard="NewsML-G2" standardversion="2.35" conformance="power" version="1"`). `NarModel.lutaml_default_register` binds symbol-typed attributes to the `:newsmlg2` context (chemicalml `Context` pattern).
|
|
59
|
+
- **`ItemSet`** — typed the mml CommonElements way: one collection attribute + `map_element` per carried item type, types as registry symbols (`:"newsItem"`).
|
|
60
|
+
- **Catalog system** — `CatalogStore` (per-document), `Catalog`/`CatalogRef`/`Scheme`, bundled IPTC catalogs (`lib/newsmlg2/catalogs/*.xml`, v32–v41), `Newsmlg2.qcode_to_uri` / `uri_to_qcode`, errors `AliasNotFoundInCatalogs` / `URINotFoundInCatalogs`.
|
|
61
|
+
- **Builder DSL** — `Newsmlg2.build_news_item(guid: …, lang: "en-GB") { |item| … }` (one `build_*` per item type). Node proxies are **generated from the model's lutaml attribute metadata** (snake_case methods, value coercion String→content-model, nested blocks, repeatable calls for collections). No per-class hand-written builder code.
|
|
62
|
+
|
|
63
|
+
### Test tiers (all must stay green)
|
|
64
|
+
|
|
65
|
+
1. **Ported python suite** — `spec/newsmlg2/**` mirroring `python-newsmlg2/tests/test_*.py` one-to-one (semantics preserved, Ruby idioms).
|
|
66
|
+
2. **IPTC examples** — `spec/compliance/examples_spec.rb` over vendored `spec/fixtures/iptc/examples/` (31 LISTING files + extras): parse → typed assertions → semantic round-trip via canon.
|
|
67
|
+
3. **IPTC official validation suite** — `spec/compliance/xsd_validation_spec.rb` over `spec/fixtures/iptc/unit_test_files/` (151 should-pass / 10 should-fail) × per-version XSDs from `tests/schema_versions/`, using `Lutaml::Xml::XsdValidator`; the file→schema matrix mirrors `tests/runtests.py` exactly.
|
|
68
|
+
|
|
69
|
+
## Conventions
|
|
70
|
+
|
|
71
|
+
- Specs use **real model instances — never doubles**; assert behavior and output, not interactions.
|
|
72
|
+
- **NEVER reference nokogiri (or any specific XML parser) in `lib/`** — specs only. All raw XML handling goes through lutaml-model's configured adapter (`Lutaml::Model::Config.adapter_for(:xml)`) or, better, `from_xml`/`to_xml` on models.
|
|
73
|
+
- **NEVER hand-roll element-name dispatch** (no name→class hashes, no `node.name` comparisons in code). Element names live only in the `xml do` DSL and the `Configuration` registration block; dispatch goes through the registry / framework mappings.
|
|
74
|
+
- **NEVER reimplement framework mechanics** (parsing, polymorphic dispatch, serialization) — read `~/src/lutaml/lutaml-model/docs/` and follow `~/src/plurimath/mml/`.
|
|
75
|
+
- Gemspec/workflows follow chemicalml verbatim (adapted names): `required_ruby_version >= 3.3.0`, single runtime dep `lutaml-model ~> 0.8.0`, `BSD-2-Clause`, Ribose Inc.
|
|
76
|
+
- Versions, tags, and releases are **the user's decision** — the release workflow is manually dispatched; never pick a version number.
|
|
77
|
+
- All changes go through PRs; never commit/push to main or push tags.
|
data/Gemfile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
gem 'rake', '~> 13.2'
|
|
8
|
+
|
|
9
|
+
group :development do
|
|
10
|
+
gem 'canon', '0.2.12'
|
|
11
|
+
gem 'nokogiri'
|
|
12
|
+
gem 'rspec', '~> 3.13'
|
|
13
|
+
gem 'rubocop', '~> 1.66', require: false
|
|
14
|
+
gem 'simplecov', '~> 0.22', require: false
|
|
15
|
+
end
|
data/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Ribose Inc.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
18
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
19
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
21
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
22
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
23
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.adoc
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
= newsmlg2
|
|
2
|
+
|
|
3
|
+
NewsML-G2 for Ruby, built on link:https://github.com/lutaml/lutaml-model[lutaml-model].
|
|
4
|
+
|
|
5
|
+
Parse, manipulate, build and serialize IPTC
|
|
6
|
+
link:https://iptc.org/standards/newsml-g2/[NewsML-G2] (News Architecture) XML
|
|
7
|
+
with round-trip fidelity. Targets specification version 2.35, power
|
|
8
|
+
conformance. The model layer is a port of
|
|
9
|
+
link:https://github.com/iptc/python-newsmlg2[python-newsmlg2], its full test
|
|
10
|
+
suite is ported, and the official IPTC specification examples and unit-test
|
|
11
|
+
suite are adopted as compliance fixtures.
|
|
12
|
+
|
|
13
|
+
== Installation
|
|
14
|
+
|
|
15
|
+
.....
|
|
16
|
+
gem "newsmlg2"
|
|
17
|
+
.....
|
|
18
|
+
|
|
19
|
+
== Parsing
|
|
20
|
+
|
|
21
|
+
.....
|
|
22
|
+
require "newsmlg2"
|
|
23
|
+
|
|
24
|
+
doc = Newsmlg2.parse_file("newsitem.xml") # or Newsmlg2.parse(xml_string)
|
|
25
|
+
doc.item # => Newsmlg2::NewsItem (typed)
|
|
26
|
+
doc.item.item_meta.item_class.qcode # => "ninat:text"
|
|
27
|
+
doc.item.content_meta.headlines.first.to_s # => "Fed to halt QE ..."
|
|
28
|
+
.....
|
|
29
|
+
|
|
30
|
+
Every root element dispatches to its typed model: +NewsItem+, +PackageItem+,
|
|
31
|
+
+ConceptItem+, +KnowledgeItem+, +CatalogItem+, +PlanningItem+ or
|
|
32
|
+
+NewsMessage+.
|
|
33
|
+
|
|
34
|
+
== QCodes and catalogs
|
|
35
|
+
|
|
36
|
+
A document carries its own catalog store: inline +<catalog>+ elements plus
|
|
37
|
+
+<catalogRef>+ hrefs (the IPTC standard catalogs are bundled, so no network
|
|
38
|
+
access is needed).
|
|
39
|
+
|
|
40
|
+
.....
|
|
41
|
+
doc.catalog_store.get_scheme_for_alias("ninat").uri
|
|
42
|
+
# => "http://cv.iptc.org/newscodes/ninature/"
|
|
43
|
+
|
|
44
|
+
Newsmlg2.qcode_to_uri("ninat:text", doc)
|
|
45
|
+
# => "http://cv.iptc.org/newscodes/ninature/text"
|
|
46
|
+
Newsmlg2.uri_to_qcode("http://cv.iptc.org/newscodes/ninature/text", doc)
|
|
47
|
+
# => "ninat:text"
|
|
48
|
+
.....
|
|
49
|
+
|
|
50
|
+
== Building with the DSL
|
|
51
|
+
|
|
52
|
+
.....
|
|
53
|
+
doc = Newsmlg2.build_news_item(guid: "urn:newsml:acme.com:20260830:00001",
|
|
54
|
+
lang: "en-GB") do |item|
|
|
55
|
+
item.item_meta do |meta|
|
|
56
|
+
meta.item_class qcode: "ninat:text"
|
|
57
|
+
meta.provider qcode: "nprov:acme" do |p|
|
|
58
|
+
p.name "Acme News Agency"
|
|
59
|
+
end
|
|
60
|
+
meta.version_created "2026-08-30T12:00:00+00:00"
|
|
61
|
+
end
|
|
62
|
+
item.content_meta do |cm|
|
|
63
|
+
cm.urgency 2
|
|
64
|
+
cm.headline "Eruption of Icelandic volcano"
|
|
65
|
+
cm.subject qcode: "medtop:20000962" do |s|
|
|
66
|
+
s.name "Volcano"
|
|
67
|
+
s.name "Vulkan", xml_lang: "de"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
doc.to_xml # => "<?xml version=\"1.0\" ... ?>"
|
|
73
|
+
.....
|
|
74
|
+
|
|
75
|
+
Builder methods are generated from the model metadata: one per attribute
|
|
76
|
+
(collections accept repeated calls and singular aliases — +subject+ appends
|
|
77
|
+
to +subjects+), keyword arguments become child attributes, plain strings
|
|
78
|
+
wrap into content-bearing types, and blocks nest.
|
|
79
|
+
|
|
80
|
+
== Serialization
|
|
81
|
+
|
|
82
|
+
.....
|
|
83
|
+
doc.to_xml # declaration + canonical 2-space-pretty XML
|
|
84
|
+
doc.item.item_meta.to_xml # any subtree
|
|
85
|
+
.....
|
|
86
|
+
|
|
87
|
+
Serializing an item without a +guid+ raises +Newsmlg2::MissingGuidError+.
|
|
88
|
+
The spec's default attributes (+standard+, +standardversion+,
|
|
89
|
+
+conformance+, +version+) are filled in like python-newsmlg2 does.
|
|
90
|
+
|
|
91
|
+
== Architecture
|
|
92
|
+
|
|
93
|
+
* +lib/newsmlg2/nar_model.rb+ — the base model: binds the NAR namespace
|
|
94
|
+
once and provides the declaration DSL (+xml_attributes+, +xml_element+,
|
|
95
|
+
+xml_content+).
|
|
96
|
+
* +lib/newsmlg2/base/+ — XSD attribute groups and element groups as mixins
|
|
97
|
+
(one file per group, ported from python-newsmlg2's attributegroups.py and
|
|
98
|
+
the +*Group+ element lists).
|
|
99
|
+
* +lib/newsmlg2/types/+ — one class per XSD complex type; element names are
|
|
100
|
+
declared once, at their usage site in the owning model.
|
|
101
|
+
* +lib/newsmlg2/items/+ — the seven item types, +newsMessage+, and their
|
|
102
|
+
structural children (+ItemMeta+, +ContentMeta+, +PartMeta+, +GroupSet+ …).
|
|
103
|
+
* +lib/newsmlg2/catalog_store.rb+ — per-document catalog store and qcode
|
|
104
|
+
resolution; IPTC catalogs v32–v41 are bundled under
|
|
105
|
+
+lib/newsmlg2/catalogs/+.
|
|
106
|
+
* +lib/newsmlg2/document.rb+ — the parse/serialize entry point.
|
|
107
|
+
* +lib/newsmlg2/builder.rb+ — the reflection-driven build DSL.
|
|
108
|
+
|
|
109
|
+
== Compliance
|
|
110
|
+
|
|
111
|
+
Three test tiers, all green in CI:
|
|
112
|
+
|
|
113
|
+
1. **python-newsmlg2 test suite port** — +spec/newsmlg2/*_spec.rb+.
|
|
114
|
+
2. **IPTC official examples** — all 35 example documents
|
|
115
|
+
(+spec/compliance/examples_spec.rb+).
|
|
116
|
+
3. **IPTC official validation suite** — 161 should-pass/should-fail files
|
|
117
|
+
across all schema versions, ~2100 assertions
|
|
118
|
+
(+spec/compliance/xsd_validation_spec.rb+).
|
|
119
|
+
|
|
120
|
+
IPTC material (examples, schemas, unit-test files) is vendored under
|
|
121
|
+
+spec/fixtures/iptc/+ under the IPTC's CC-BY 4.0 / MIT terms; see
|
|
122
|
+
+spec/fixtures/iptc/README.md+.
|
|
123
|
+
|
|
124
|
+
== Development
|
|
125
|
+
|
|
126
|
+
.....
|
|
127
|
+
bundle install
|
|
128
|
+
bundle exec rake # full suite
|
|
129
|
+
bundle exec rubocop
|
|
130
|
+
.....
|
|
131
|
+
|
|
132
|
+
== License
|
|
133
|
+
|
|
134
|
+
BSD-2-Clause. NewsML-G2 is a trademark of the IPTC; this library is not
|
|
135
|
+
affiliated with the IPTC.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
|
|
5
|
+
Dir[File.expand_path('lib/tasks/*.rake', __dir__)].each { |task| import task }
|
|
6
|
+
|
|
7
|
+
begin
|
|
8
|
+
require 'rspec/core/rake_task'
|
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
10
|
+
task default: :spec
|
|
11
|
+
rescue LoadError
|
|
12
|
+
task :default do
|
|
13
|
+
warn 'rspec not available — skipping specs'
|
|
14
|
+
end
|
|
15
|
+
end
|
data/docs/Gemfile
ADDED
data/docs/_config.yml
ADDED
data/docs/index.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: newsmlg2 — NewsML-G2 for Ruby
|
|
3
|
+
layout: default
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# newsmlg2
|
|
7
|
+
|
|
8
|
+
NewsML-G2 for Ruby, built on [lutaml-model](https://github.com/lutaml/lutaml-model).
|
|
9
|
+
|
|
10
|
+
See the [README](https://github.com/lutaml/newsmlg2-ruby) for usage:
|
|
11
|
+
parsing, qcode/catalog resolution, the builder DSL and serialization.
|
|
12
|
+
|
|
13
|
+
## Pages
|
|
14
|
+
|
|
15
|
+
- [Usage](usage.md)
|
data/docs/lychee.toml
ADDED