Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/uniword.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,16 @@ module Uniword
# directly, falling back to :default for Uniword's own types. Setting
# Config.default_register means from_xml/to_xml calls without an explicit
# register: argument use :uniword automatically.
#
# OmmlIntegration (autoloaded below) then substitutes omml's minimal
# WordprocessingML stubs with Uniword's richer classes via the Register's
# type substitution mechanism — single source of truth for WordprocessingML.
require "omml"
Omml::Configuration.register_in(:uniword)
Lutaml::Model::Config.default_register = :uniword

autoload :OmmlIntegration, "uniword/omml_integration"

# Version constant
autoload :VERSION, "uniword/version"
autoload :ModelAttributeAccess, "uniword/model_attribute_access"
Expand Down Expand Up @@ -344,4 +350,8 @@ def html_to_docx(html, path)
from_html(html).to_file(path)
end
end

# Register WordprocessingML substitutions after autoloads are declared
# so OmmlIntegration can resolve Uniword class constants via const_get.
OmmlIntegration.register
end
62 changes: 62 additions & 0 deletions lib/uniword/omml_integration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

require "omml"

module Uniword
# Registers Uniword's WordprocessingML classes as substitutions for
# Omml::Models' minimal WordprocessingML stubs. When an Omml model
# (e.g. CTOMath) resolves a WordprocessingML type symbol (e.g.
# +:ct_br+), the Register's substitution table redirects resolution
# to the corresponding Uniword class.
#
# This keeps a single source of truth for WordprocessingML types:
# Uniword owns the rich, builder-friendly classes; omml owns the math
# schema. The two meet through register substitution, not through
# duplicate model definitions.
module OmmlIntegration
SUBSTITUTIONS = {
"Omml::Models::CTBr" => "Uniword::Wordprocessingml::Break",
}.freeze

class << self
def register
ensure_omml_context
register_substitutions
end

private

def ensure_omml_context
return if Lutaml::Model::GlobalContext.context(:uniword)

Omml::Configuration.register_in(:uniword)
Lutaml::Model::Config.default_register = :uniword
end

def register_substitutions
register_handle = Lutaml::Model::GlobalRegister.lookup(:uniword)
return unless register_handle

SUBSTITUTIONS.each do |omml_class_name, uniword_class_name|
omml_class = constantize(omml_class_name)
uniword_class = constantize(uniword_class_name)
next unless omml_class && uniword_class

register_handle.register_global_type_substitution(
from_type: omml_class,
to_type: uniword_class,
)
end
end

def constantize(class_name)
parts = class_name.split("::")
parts.reduce(Object) do |scope, part|
scope.const_get(part)
end
rescue NameError
nil
end
end
end
end
Loading