Module: Yaml::Converter
- Defined in:
- lib/yaml/converter.rb,
lib/yaml/converter/config.rb,
lib/yaml/converter/parser.rb,
lib/yaml/converter/version.rb,
lib/yaml/converter/validation.rb,
lib/yaml/converter/state_machine.rb,
lib/yaml/converter/markdown_emitter.rb,
lib/yaml/converter/streaming_emitter.rb,
lib/yaml/converter/renderer/pdf_prawn.rb,
lib/yaml/converter/renderer/pandoc_shell.rb
Defined Under Namespace
Modules: Config, Renderer, Validation, Version Classes: Error, InvalidArgumentsError, MarkdownEmitter, PandocNotFoundError, Parser, RendererUnavailableError, StateMachine, StreamingEmitter
Constant Summary collapse
Class Method Summary collapse
-
.convert(input_path:, output_path:, options: {}) ⇒ Hash
Convert a YAML file to a target format determined by the output extension.
-
.to_markdown(yaml_string, options: {}) ⇒ String
Convert a YAML string into Markdown with optional validation & notes extraction.
-
.to_markdown_streaming(input_path, io, options: {}) ⇒ void
Stream a YAML file to Markdown into an IO target.
-
.validate(yaml_string) ⇒ Hash{Symbol=>Object}
Validate a YAML string returning a structured status.
Class Method Details
.convert(input_path:, output_path:, options: {}) ⇒ Hash
Convert a YAML file to a target format determined by the output extension.
Supported extensions (Phase 1): .md, .html, .pdf (native), .docx (pandoc).
Other formats may be produced via pandoc when :use_pandoc is true.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/yaml/converter.rb', line 97 def convert(input_path:, output_path:, options: {}) raise InvalidArgumentsError, "input file not found: #{input_path}" unless File.exist?(input_path) ext = File.extname(output_path) if ext == ".yaml" raise InvalidArgumentsError, "Output must not be .yaml" end opts = Config.resolve() yaml_string = nil if File.exist?(output_path) && ENV["KETTLE_TEST_SILENT"] != "true" warn("Overwriting existing file: #{output_path}") end auto_stream = !opts[:streaming] && File.size?(input_path) && File.size(input_path) >= opts[:streaming_threshold_bytes] if ext == ".md" || ext == "" # Direct markdown output path: stream to file for large inputs File.open(output_path, "w") do |io| if opts[:streaming] || auto_stream to_markdown_streaming(input_path, io, options: opts) else yaml_string = File.read(input_path) io.write(to_markdown(yaml_string, options: opts)) end end validation_result = if opts[:validate] yaml_string ? Validation.validate_string(yaml_string) : Validation.validate_file(input_path) else {status: :ok, error: nil} end return {status: :ok, output_path: output_path, validation: validation_result} end # For non-markdown outputs, we still produce an intermediate markdown string. yaml_string = File.read(input_path) if yaml_string.nil? markdown = to_markdown(yaml_string, options: opts) # Helper lambda to build standard success response success = lambda do {status: :ok, output_path: output_path, validation: (opts[:validate] ? Validation.validate_string(yaml_string) : {status: :ok, error: nil})} end case ext when ".html" require "kramdown" require "kramdown-parser-gfm" body_html = Kramdown::Document.new(markdown, input: "GFM").to_html note_style = "" if markdown.include?("> NOTE:") note_style = "<style>.yaml-note{font-style:italic;color:#555;margin-left:1em;}</style>\n" body_html = body_html.gsub("<blockquote>", '<blockquote class="yaml-note">') end html = <<~HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"> #{note_style}</head> <body> #{body_html} </body> </html> HTML File.write(output_path, html) success.call when ".pdf" if opts[:use_pandoc] tmp_md = output_path + ".md" File.write(tmp_md, markdown) require_relative "converter/renderer/pandoc_shell" ok = Renderer::PandocShell.render(md_path: tmp_md, out_path: output_path, pandoc_path: opts[:pandoc_path], args: opts[:pandoc_args]) File.delete(tmp_md) if File.exist?(tmp_md) raise PandocNotFoundError, "pandoc not found in PATH" unless ok else require_relative "converter/renderer/pdf_prawn" ok = Renderer::PdfPrawn.render(markdown: markdown, out_path: output_path, options: opts) raise RendererUnavailableError, "PDF rendering failed" unless ok end success.call when ".docx" tmp_md = output_path + ".md" File.write(tmp_md, markdown) require_relative "converter/renderer/pandoc_shell" pandoc_path = Renderer::PandocShell.which("pandoc") if pandoc_path ok = Renderer::PandocShell.render(md_path: tmp_md, out_path: output_path, pandoc_path: pandoc_path, args: []) File.delete(tmp_md) if File.exist?(tmp_md) raise RendererUnavailableError, "pandoc failed to generate DOCX" unless ok success.call else File.delete(tmp_md) if File.exist?(tmp_md) raise RendererUnavailableError, "DOCX requires pandoc; install pandoc or use .md/.html/.pdf" end else tmp_md = output_path + ".md" File.write(tmp_md, markdown) if opts[:use_pandoc] require_relative "converter/renderer/pandoc_shell" ok = Renderer::PandocShell.render(md_path: tmp_md, out_path: output_path, pandoc_path: opts[:pandoc_path], args: opts[:pandoc_args]) File.delete(tmp_md) if File.exist?(tmp_md) raise PandocNotFoundError, "pandoc not found in PATH" unless ok success.call else raise RendererUnavailableError, "Renderer for #{ext} not implemented. Pass use_pandoc: true or use .md/.html/.pdf." end end end |
.to_markdown(yaml_string, options: {}) ⇒ String
Convert a YAML string into Markdown with optional validation & notes extraction.
38 39 40 41 42 43 44 45 46 47 |
# File 'lib/yaml/converter.rb', line 38 def to_markdown(yaml_string, options: {}) opts = Config.resolve() emitter = MarkdownEmitter.new(opts) if opts[:validate] validation = Validation.validate_string(yaml_string) status = (validation && validation[:status] == :ok) ? :ok : :fail emitter.set_validation_status(status) end emitter.emit(yaml_string.lines).join("\n") end |
.to_markdown_streaming(input_path, io, options: {}) ⇒ void
This method returns an undefined value.
Stream a YAML file to Markdown into an IO target.
Automatically injects validation status if enabled.
55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/yaml/converter.rb', line 55 def to_markdown_streaming(input_path, io, options: {}) opts = Config.resolve() emitter = StreamingEmitter.new(opts, io) if opts[:validate] validation = Validation.validate_file(input_path) status = (validation && validation[:status] == :ok) ? :ok : :fail emitter.set_validation_status(status) end emitter.emit_file(input_path) nil end |
.validate(yaml_string) ⇒ Hash{Symbol=>Object}
Validate a YAML string returning a structured status.
73 74 75 |
# File 'lib/yaml/converter.rb', line 73 def validate(yaml_string) Validation.validate_string(yaml_string) end |