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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41c7086b0f760b06a87c99ce115f66d31c1a8e30a6f43a182e1ed81a076b0ee6
4
- data.tar.gz: a55d956d5122b77c0078b9d48adb4c4c3b6c97b1c7638498a8a9d31d342b799b
3
+ metadata.gz: 68e4e30c0ecd25f66ab9f39d7132b23d05f3266a5afba3a6e67f91916329385c
4
+ data.tar.gz: 3d9d4072b81250ec95cb81d7630eeaaf1115338ba24469ee62a58d25bbfe8910
5
5
  SHA512:
6
- metadata.gz: c37685805cfcff21fe4bb18e2a17661242c36a7605aa257736875c5735870e875fcfeb399f3769c25cd8ec4515a68561f8bcc8a503b970c805fe04251e2c2f6f
7
- data.tar.gz: 4ce50e2bba70f304654640489d89a8d3e9fe45b2e42c3b34f634985b8d79db23bdb5f9e2f2da15bda5fdd6da9b0089b344657e9cbc131ce26d80a0011662ac82
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
@@ -1,5 +1,5 @@
1
1
  module Metanorma
2
2
  module Core
3
- VERSION = "0.2.3".freeze
3
+ VERSION = "0.2.4".freeze
4
4
  end
5
5
  end
@@ -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.3
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: 1980-01-02 00:00:00.000000000 Z
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: 4.0.16
206
+ rubygems_version: 3.5.22
207
+ signing_key:
202
208
  specification_version: 4
203
209
  summary: Metanorma Core
204
210
  test_files: []