Module: Coradoc::Pipeline

Defined in:
lib/coradoc/pipeline.rb

Overview

Parse / serialize / convert pipeline. Single source of truth for the document transformation flow, extracted from the top-level Coradoc façade so pipeline logic has its own home and its own spec surface. Public API on Coradoc delegates here.

Class Method Summary collapse

Class Method Details

.build(&block) ⇒ Object



76
77
78
# File 'lib/coradoc/pipeline.rb', line 76

def build(&block)
  CoreModel::DocumentElement.build(children: [], &block)
end

.convert(text, from:, to:) ⇒ Object



50
51
52
53
# File 'lib/coradoc/pipeline.rb', line 50

def convert(text, from:, to:, **)
  core = parse(text, format: from)
  serialize(core, to: to, **)
end

.convert_file(path, to:, from: nil) ⇒ Object



99
100
101
102
103
104
105
# File 'lib/coradoc/pipeline.rb', line 99

def convert_file(path, to:, from: nil, **)
  source_format = from || FormatCatalog.detect_format(path)
  raise UnsupportedFormatError, "Could not detect format for: #{path}" unless source_format

  core = parse_file(path, format: source_format)
  serialize(core, to: to, **)
end

.parse(text, format:) ⇒ Object

Parse text to a document model. Graph mode: include:: directives survive as CoreModel::Include link nodes — no file I/O happens during parse. Splicing included content is a separate, explicit step (see Coradoc.resolve_includes).



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/coradoc/pipeline.rb', line 14

def parse(text, format:)
  format_module = FormatCatalog.get_format(format)
  unless format_module
    raise UnsupportedFormatError,
          "Format '#{format}' is not registered. " \
          "Available formats: #{FormatCatalog.registered_formats.join(', ')}"
  end

  text = Hooks.invoke(:before_parse, text, format: format)
  result = format_module.parse_to_core(text)
  Hooks.invoke(:after_parse, result, format: format)
end

.parse_file(path, format: nil) ⇒ Object

Raises:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/coradoc/pipeline.rb', line 80

def parse_file(path, format: nil)
  raise FileNotFoundError, path unless File.exist?(path)

  source_format = format || FormatCatalog.detect_format(path)
  raise UnsupportedFormatError, "Could not detect format for: #{path}" unless source_format

  format_module = FormatCatalog.get_format(source_format)
  raise UnsupportedFormatError, "Format '#{source_format}' is not registered" unless format_module

  if FormatCatalog.binary_format?(source_format)
    format_module.parse_to_core(path)
  else
    content = File.read(path)
    content = Hooks.invoke(:before_parse, content, format: source_format)
    result = format_module.parse_file_to_core(path, content)
    Hooks.invoke(:after_parse, result, format: source_format)
  end
end

.resolve_includes(document, base_dir:, missing_include: :error, max_depth: Coradoc::ResolveIncludes::DEFAULT_MAX_DEPTH, allow_unsafe: false, resolver: nil) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/coradoc/pipeline.rb', line 27

def resolve_includes(document, base_dir:,
                     missing_include: :error,
                     max_depth: Coradoc::ResolveIncludes::DEFAULT_MAX_DEPTH,
                     allow_unsafe: false,
                     resolver: nil)
  resolver = Coradoc::IncludeResolver.coerce(
    resolver,
    base_dir: base_dir,
    allow_unsafe: allow_unsafe
  )
  Coradoc::ResolveIncludes.call(
    document,
    resolver: resolver,
    base_dir: base_dir,
    missing_include: missing_include,
    max_depth: max_depth
  )
end


46
47
48
# File 'lib/coradoc/pipeline.rb', line 46

def rewrite_links(document, rewriter: nil, &block)
  Coradoc::LinkRewriter.rewrite(document, rewriter: rewriter, &block)
end

.serialize(model, to:) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/coradoc/pipeline.rb', line 67

def serialize(model, to:, **)
  format_module = FormatCatalog.get_format(to)
  raise UnsupportedFormatError, "Format '#{to}' is not registered" unless format_module

  model = Hooks.invoke(:before_serialize, model, format: to)
  result = format_module.serialize(model, **)
  Hooks.invoke(:after_serialize, result, format: to)
end

.to_core(model) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/coradoc/pipeline.rb', line 55

def to_core(model)
  return model if model.is_a?(CoreModel::Base)

  FormatCatalog.registry.each_value do |format_module|
    next unless format_module.handles_model?(model)

    return format_module.to_core(model)
  end

  raise TransformationError, "No transformer found for #{model.class}"
end