metanorma-core 0.2.3 → 0.2.4
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 +4 -4
- data/README.adoc +2 -0
- data/lib/metanorma/core/flavor.rb +89 -0
- data/lib/metanorma/core/flavor_loader.rb +6 -0
- data/lib/metanorma/core/flavor_registry.rb +56 -0
- data/lib/metanorma/core/flavors.rb +63 -0
- data/lib/metanorma/core/version.rb +1 -1
- data/lib/metanorma-core.rb +3 -0
- metadata +9 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 68e4e30c0ecd25f66ab9f39d7132b23d05f3266a5afba3a6e67f91916329385c
|
|
4
|
+
data.tar.gz: 3d9d4072b81250ec95cb81d7630eeaaf1115338ba24469ee62a58d25bbfe8910
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 002dd0efbf7c11b30d665b62f377fac848f3636448728ee01012062b332c5e33bec62523f2b6ff194f2c6651efcec93ec24ad33edfeeb11212be9e00fb1b3e90
|
|
7
|
+
data.tar.gz: e2ebc0042409579e2f17312a96b6f8c77a8247235d243500d4f888282738aaf83bda659dfa6a77ab93010fd4675ed1230c426cc50696070e8a1fba740c30f66d
|
data/README.adoc
CHANGED
|
@@ -11,3 +11,5 @@ image:https://img.shields.io/github/commits-since/metanorma/metanorma-core/lates
|
|
|
11
11
|
|
|
12
12
|
This is a core repository for plugin dependencies of Metanorma, allowing metanorma-standoc and metanorma to share code without circular dependencies.
|
|
13
13
|
|
|
14
|
+
|
|
15
|
+
<!-- canary: automerge stub verification, revert not needed -->
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
module Core
|
|
5
|
+
# One entry in the flavor/taste table — the single source of truth
|
|
6
|
+
# for flavor identity across the ecosystem.
|
|
7
|
+
#
|
|
8
|
+
# A FLAVOR entry (base_flavor nil): a document model family — model
|
|
9
|
+
# root, processor, per-format renderers, pubid module, gem name.
|
|
10
|
+
# A TASTE entry (base_flavor set): a config-only variant of a flavor
|
|
11
|
+
# — no model of its own; it carries the publisher discriminator,
|
|
12
|
+
# branding directory, and doctype map, and inherits everything else
|
|
13
|
+
# through its base chain.
|
|
14
|
+
#
|
|
15
|
+
# renderers values: a renderer class, or a Proc resolver taking
|
|
16
|
+
# (document, **options) and returning a class — flavor-owned variant
|
|
17
|
+
# selection (publisher/profile/doctype). Returning nil falls through
|
|
18
|
+
# to the next matching entry.
|
|
19
|
+
class Flavor
|
|
20
|
+
attr_reader :name, :base_flavor, :gem, :model_root, :processor,
|
|
21
|
+
:renderers, :pubid_module, :branding_dir,
|
|
22
|
+
:publisher_abbr, :doctype_map, :semantic_input
|
|
23
|
+
|
|
24
|
+
def initialize(name:, base_flavor: nil, gem: nil, model_root: nil,
|
|
25
|
+
processor: nil, renderers: {}, pubid_module: nil,
|
|
26
|
+
branding_dir: nil, publisher_abbr: nil, doctype_map: {},
|
|
27
|
+
semantic_input: false)
|
|
28
|
+
@name = name&.to_sym
|
|
29
|
+
@base_flavor = base_flavor&.to_sym
|
|
30
|
+
@gem = gem || "metanorma-#{name}"
|
|
31
|
+
@model_root = model_root
|
|
32
|
+
@processor = processor
|
|
33
|
+
@renderers = renderers
|
|
34
|
+
@pubid_module = pubid_module
|
|
35
|
+
@branding_dir = branding_dir
|
|
36
|
+
@publisher_abbr = publisher_abbr
|
|
37
|
+
@doctype_map = doctype_map
|
|
38
|
+
@semantic_input = semantic_input
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def taste? = !!base_flavor
|
|
42
|
+
|
|
43
|
+
def renderer_for(format, document, **options)
|
|
44
|
+
entry = renderers[format]
|
|
45
|
+
return nil unless entry
|
|
46
|
+
|
|
47
|
+
entry.is_a?(Proc) ? entry.call(document, **options) : entry
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def matches?(document_class)
|
|
51
|
+
return false unless document_class.is_a?(Class)
|
|
52
|
+
|
|
53
|
+
root = model_root_class
|
|
54
|
+
return false unless root
|
|
55
|
+
|
|
56
|
+
!!(document_class <= root)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def model_root_class
|
|
60
|
+
return @model_root_class if @model_root_class
|
|
61
|
+
|
|
62
|
+
# Never cache a miss: the flavor gem may load after the first
|
|
63
|
+
# lookup (lazy string roots resolve once the owning gem is
|
|
64
|
+
# required), and a cached nil would poison every later walk.
|
|
65
|
+
klass = if model_root.is_a?(Class)
|
|
66
|
+
model_root
|
|
67
|
+
elsif model_root && Object.const_defined?(model_root)
|
|
68
|
+
Object.const_get(model_root)
|
|
69
|
+
end
|
|
70
|
+
@model_root_class = klass
|
|
71
|
+
klass
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def pubid_module_const
|
|
75
|
+
return nil unless pubid_module
|
|
76
|
+
|
|
77
|
+
begin
|
|
78
|
+
require "pubid"
|
|
79
|
+
rescue LoadError
|
|
80
|
+
return nil
|
|
81
|
+
end
|
|
82
|
+
Object.const_get(pubid_module.to_s)
|
|
83
|
+
rescue NameError
|
|
84
|
+
raise ArgumentError,
|
|
85
|
+
"Flavor #{name.inspect}: pubid module #{pubid_module} could " "not be resolved — fix the flavor's registration"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -27,6 +27,12 @@ module Metanorma
|
|
|
27
27
|
# taste alias matched).
|
|
28
28
|
def taste2flavor(stdtype)
|
|
29
29
|
stdtype = stdtype.to_sym
|
|
30
|
+
entry = Flavors.find(stdtype)
|
|
31
|
+
return entry.base_flavor if entry&.taste?
|
|
32
|
+
|
|
33
|
+
# Transitional: taste entries land in the table with
|
|
34
|
+
# metanorma-taste's restructure PR; until then fall back to
|
|
35
|
+
# TasteRegister.aliases. Removed in this branch's final commit.
|
|
30
36
|
tastes = Metanorma::TasteRegister.instance.aliases
|
|
31
37
|
tastes[stdtype] and stdtype = tastes[stdtype].to_sym
|
|
32
38
|
stdtype
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
module Core
|
|
5
|
+
# The process-wide flavor/taste table. Registered most-specific-last;
|
|
6
|
+
# resolution walks most-specific-first so flavor gems (loaded after
|
|
7
|
+
# the harness defaults) win, and taste entries fall through to their
|
|
8
|
+
# base chain by yielding nil.
|
|
9
|
+
class FlavorRegistry
|
|
10
|
+
include Enumerable
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@flavors = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def register(flavor)
|
|
17
|
+
@flavors << flavor
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def each(&) = @flavors.each(&)
|
|
22
|
+
|
|
23
|
+
def find_by_name(name)
|
|
24
|
+
@flavors.reverse_each.find { |f| f.name == name.to_sym }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def flavor_for(document)
|
|
28
|
+
@flavors.reverse_each.find { |f| f.matches?(document.class) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Renderer class for (document, format): walk matching entries
|
|
32
|
+
# most-specific-first; a taste without its own renderer for the
|
|
33
|
+
# format yields nil and falls through to the base flavor entry.
|
|
34
|
+
def renderer_for(format, document, **options)
|
|
35
|
+
@flavors.reverse_each.each do |flavor|
|
|
36
|
+
next unless flavor.matches?(document.class)
|
|
37
|
+
|
|
38
|
+
renderer = flavor.renderer_for(format, document, **options)
|
|
39
|
+
return renderer if renderer
|
|
40
|
+
end
|
|
41
|
+
nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Canonical FLAVOR entry for a stdtype/taste name: follows the
|
|
45
|
+
# base_flavor chain so compile loads the base flavor's gem and
|
|
46
|
+
# processor while the taste supplies config.
|
|
47
|
+
def canonical(name)
|
|
48
|
+
entry = find_by_name(name)
|
|
49
|
+
return nil unless entry
|
|
50
|
+
|
|
51
|
+
entry = find_by_name(entry.base_flavor) while entry&.base_flavor
|
|
52
|
+
entry
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
module Core
|
|
5
|
+
# The composition-layer API over the flavor/taste table. Replaces
|
|
6
|
+
# the former scattered mechanisms: Registry-only processor dispatch,
|
|
7
|
+
# FlavorLoader.taste2flavor, CLI hand-merged dictionaries, and the
|
|
8
|
+
# renderer registries the harness once carried.
|
|
9
|
+
module Flavors
|
|
10
|
+
class << self
|
|
11
|
+
def table
|
|
12
|
+
@table ||= FlavorRegistry.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def register(flavor)
|
|
16
|
+
table.register(flavor)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Compile-time: canonical flavor entry for a stdtype name
|
|
20
|
+
# (taste chains resolved), loading its gem if needed.
|
|
21
|
+
def resolve(type)
|
|
22
|
+
canonical = table.canonical(type)
|
|
23
|
+
return nil unless canonical
|
|
24
|
+
|
|
25
|
+
unless backends.include?(canonical.name)
|
|
26
|
+
require canonical.gem
|
|
27
|
+
end
|
|
28
|
+
canonical
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Render-time: renderer class for (document, format).
|
|
32
|
+
def renderer_for(document, format:, **options)
|
|
33
|
+
table.renderer_for(format, document, **options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def flavor_for(document)
|
|
37
|
+
table.flavor_for(document)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def find(name)
|
|
41
|
+
table.find_by_name(name)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Tastes of a given base flavor (for dictionaries/projections).
|
|
45
|
+
def tastes_of(base)
|
|
46
|
+
table.select { |f| f.taste? && f.base_flavor == base.to_sym }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def available_tastes
|
|
50
|
+
table.select(&:taste?).map(&:name)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def backends
|
|
56
|
+
Metanorma::Registry.instance.supported_backends
|
|
57
|
+
rescue NameError
|
|
58
|
+
[]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/metanorma-core.rb
CHANGED
|
@@ -8,6 +8,9 @@ require "metanorma/input"
|
|
|
8
8
|
require "metanorma/processor/processor"
|
|
9
9
|
require "metanorma/registry/registry"
|
|
10
10
|
require "metanorma/asciidoctor_extensions"
|
|
11
|
+
require "metanorma/core/flavor"
|
|
12
|
+
require "metanorma/core/flavor_registry"
|
|
13
|
+
require "metanorma/core/flavors"
|
|
11
14
|
require "metanorma/core/flavor_loader"
|
|
12
15
|
require "metanorma/core/isodoc"
|
|
13
16
|
require "metanorma/core/boilerplate"
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: metanorma-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-09-29 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: asciidoctor
|
|
@@ -169,7 +170,10 @@ files:
|
|
|
169
170
|
- lib/metanorma/asciidoctor_extensions/glob_include_processor.rb
|
|
170
171
|
- lib/metanorma/config/config.rb
|
|
171
172
|
- lib/metanorma/core/boilerplate.rb
|
|
173
|
+
- lib/metanorma/core/flavor.rb
|
|
172
174
|
- lib/metanorma/core/flavor_loader.rb
|
|
175
|
+
- lib/metanorma/core/flavor_registry.rb
|
|
176
|
+
- lib/metanorma/core/flavors.rb
|
|
173
177
|
- lib/metanorma/core/isodoc.rb
|
|
174
178
|
- lib/metanorma/core/version.rb
|
|
175
179
|
- lib/metanorma/input.rb
|
|
@@ -184,6 +188,7 @@ homepage: https://github.com/metanorma/metanorma-core
|
|
|
184
188
|
licenses:
|
|
185
189
|
- BSD-2-Clause
|
|
186
190
|
metadata: {}
|
|
191
|
+
post_install_message:
|
|
187
192
|
rdoc_options: []
|
|
188
193
|
require_paths:
|
|
189
194
|
- lib
|
|
@@ -198,7 +203,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
198
203
|
- !ruby/object:Gem::Version
|
|
199
204
|
version: '0'
|
|
200
205
|
requirements: []
|
|
201
|
-
rubygems_version:
|
|
206
|
+
rubygems_version: 3.5.22
|
|
207
|
+
signing_key:
|
|
202
208
|
specification_version: 4
|
|
203
209
|
summary: Metanorma Core
|
|
204
210
|
test_files: []
|