Module: Arrolio::GenericAdapter::InlineRunCollection
- Included in:
- Arrolio::GenericAdapter
- Defined in:
- lib/arrolio/generic_adapter/inline_run_collection.rb
Overview
Extracted conversion seam (TODO 56): one module per concern, included into the adapter. The class keeps dispatch and glue.
Constant Summary collapse
- UNICODE_SPACES =
Regexp.new("[\u00A0\u1680\u2000-\u200B\u202F\u205F\u3000\uFEFF]")
Instance Method Summary collapse
- #collect_inline_runs(elem, default_style: :inline, exclude: nil, footnote_markers: false) ⇒ Object
- #format_locality_text(text) ⇒ Object
-
#normalize_text(raw) ⇒ Object
Newline-bearing text nodes keep ONE space at each boundary: 'where\n
' must render 'where Y' — stripping the trailing whitespace glued words to the following element and made long formula runs unbreakable (clipped at the page edge). - #serialize_element_to_xml(elem) ⇒ Object
-
#walk_math(elem, style, runs) ⇒ Object
Walks a MathML tree emitting InlineRuns with appropriate baseline_shift + font_size_scale.
- #walk_stem(stem_elem, style, runs, formatted_name, math_name) ⇒ Object
Instance Method Details
#collect_inline_runs(elem, default_style: :inline, exclude: nil, footnote_markers: false) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/arrolio/generic_adapter/inline_run_collection.rb', line 9 def collect_inline_runs(elem, default_style: :inline, exclude: nil, footnote_markers: false) runs = [] stem_name = selector('stem') fn_name = footnote_markers ? selector('footnote_marker') : nil stem_formatted_name = selector('stem_formatted') math_name = selector('math') tab_name = selector('tab_inline') br_name = selector('break_inline') xref_name = selector('biblio_formattedref') ? 'fmt-xref' : nil = @rules['skip_metadata_elements'].to_a block_level = @rules['block_level_elements'].to_a inline_styles = @rules['inline_styles'] || {} walker = lambda do |node, style, baseline: Content::InlineRun::BASELINE_NORMAL, scale: 1.0, in_xref: false| case node when REXML::Text raw = normalize_text(node.value) next if raw.nil? || raw.empty? text = in_xref ? format_locality_text(raw) : raw runs << Content::InlineRun.new(text, style_id: style, baseline_shift: baseline, font_size_scale: scale) when REXML::Element next if exclude && node.name == exclude if fn_name && node.name == fn_name marker = node.attribute('reference')&.value || node.attribute('id')&.value unless marker.nil? || marker.empty? runs << Content::InlineRun.new( marker, style_id: style, baseline_shift: Content::InlineRun::BASELINE_SUP, font_size_scale: 0.7 ) end next end new_style = resolve_inline_style(node, style) sub_baseline, sub_scale = baseline_for_style(inline_styles, node, baseline, scale) child_in_xref = in_xref || (xref_name && node.name == xref_name) case node.name when tab_name runs << Content::InlineRun.new("\t", style_id: style) when br_name runs << Content::InlineRun.new("\n", style_id: style) when stem_name unless sibling_exists?(node.parent, stem_formatted_name) walk_stem(node, style, runs, stem_formatted_name, math_name) end when stem_formatted_name walk_math(node, style, runs) when * next when *block_level next else node.children.each do |c| walker.call(c, new_style, baseline: sub_baseline, scale: sub_scale, in_xref: child_in_xref) end end end end elem.children.each { |c| walker.call(c, default_style) } runs end |
#format_locality_text(text) ⇒ Object
79 80 81 |
# File 'lib/arrolio/generic_adapter/inline_run_collection.rb', line 79 def format_locality_text(text) text.gsub(/([a-zA-Z]+)=/, '\\1 ') end |
#normalize_text(raw) ⇒ Object
Newline-bearing text nodes keep ONE space at each boundary:
'where\n
122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/arrolio/generic_adapter/inline_run_collection.rb', line 122 def normalize_text(raw) return raw unless raw.is_a?(String) cleaned = raw.gsub(UNICODE_SPACES, ' ') return cleaned unless cleaned.include?("\n") stripped = cleaned.strip return cleaned.match?(/\s/) ? ' ' : nil if stripped.empty? lead = cleaned.match?(/\A\s/) ? ' ' : '' trail = cleaned.match?(/\s\z/) ? ' ' : '' lead + stripped.gsub(/\s+/, ' ') + trail end |
#serialize_element_to_xml(elem) ⇒ Object
111 112 113 114 115 |
# File 'lib/arrolio/generic_adapter/inline_run_collection.rb', line 111 def serialize_element_to_xml(elem) io = StringIO.new(+'') REXML::Formatters::Default.new.write(elem, io) io.string end |
#walk_math(elem, style, runs) ⇒ Object
Walks a MathML tree emitting InlineRuns with appropriate baseline_shift + font_size_scale. Delegates the actual MathML parsing to the plurimath/mml gem via MathML::InlineRunExtractor, keeping this adapter free of its own MathML grammar.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/arrolio/generic_adapter/inline_run_collection.rb', line 92 def walk_math(elem, style, runs) return unless elem math_name = selector('math') math_elem = if elem.name == math_name elem else found = nil elem.each_recursive { |e| found = e if e.name == math_name && found.nil? } found end return unless math_elem math_xml = serialize_element_to_xml(math_elem) extracted = ::Arrolio::MathML::InlineRunExtractor.extract_from_xml(math_xml, base_style: style) runs.concat(extracted) end |
#walk_stem(stem_elem, style, runs, formatted_name, math_name) ⇒ Object
83 84 85 86 |
# File 'lib/arrolio/generic_adapter/inline_run_collection.rb', line 83 def walk_stem(stem_elem, style, runs, formatted_name, math_name) target = find_first(stem_elem, formatted_name) || find_first(stem_elem, math_name) walk_math(target, style, runs) if target end |