Class: Asciidoctor::Ptc::Renderer
- Inherits:
-
Object
- Object
- Asciidoctor::Ptc::Renderer
- Defined in:
- lib/asciidoctor/ptc/renderer.rb
Overview
Renders .ptc (time-current grading) source into an image file by
shelling out to the bundled Node helper (js/ptc_render.mjs). Handles
output-directory resolution and content-hash caching so an unchanged
study is only rendered once.
Unlike a renderer with no validation step of its own, a .ptc study can
be well-formed AsciiDoc and still fail to parse or grade cleanly, so
this class also carries the Node helper's verdict (resolved theme,
whether the study had errors, whether grading failed, whether the sheet
was force-rendered anyway) back to the caller — needed to label the
generated image correctly, including on a cache hit, where the helper is
not invoked at all.
Kept intentionally free of Asciidoctor-specific types so it is trivial to unit test in isolation.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- SCRIPT =
File.('js/ptc_render.mjs', __dir__)
- FORMATS =
%w[svg png pdf].freeze
- THEMES =
%w[light dark monochrome print].freeze
- ORIENTATIONS =
%w[portrait landscape].freeze
- SIZES =
Matches tc-curves' own PAPER_MM keys (src/export/export-pdf.ts).
%w[A0 A1 A2 A3 A4 A5 Letter Legal Tabloid].freeze
Instance Attribute Summary collapse
-
#all_views ⇒ Object
readonly
Returns the value of attribute all_views.
-
#format ⇒ Object
readonly
Returns the value of attribute format.
-
#grading_fails ⇒ Object
readonly
Returns the value of attribute grading_fails.
-
#has_errors ⇒ Object
readonly
Returns the value of attribute has_errors.
-
#invalid_errors ⇒ Object
readonly
Returns the value of attribute invalid_errors.
-
#margin ⇒ Object
readonly
Returns the value of attribute margin.
-
#orientation ⇒ Object
readonly
Returns the value of attribute orientation.
-
#out_dir ⇒ Object
readonly
Returns the value of attribute out_dir.
-
#resolved_height ⇒ Object
readonly
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
-
#resolved_pages ⇒ Object
readonly
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
-
#resolved_theme ⇒ Object
readonly
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
-
#resolved_width ⇒ Object
readonly
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
-
#scale ⇒ Object
readonly
Returns the value of attribute scale.
-
#size ⇒ Object
readonly
Returns the value of attribute size.
-
#theme ⇒ Object
readonly
Returns the value of attribute theme.
-
#view ⇒ Object
readonly
Returns the value of attribute view.
-
#width ⇒ Object
readonly
Returns the value of attribute width.
Instance Method Summary collapse
-
#command_for(out_path) ⇒ Object
Assemble the node command line (exposed for testing).
-
#initialize(opts = {}) ⇒ Renderer
constructor
opts is a plain Hash with symbol keys: :format, :scale, :width, :theme, :view, :background, :font_family, :force, :all_views, :size, :orientation, :margin, :node, :package_dir, :out_dir, :cache.
-
#render(source, basename = nil) ⇒ Object
Render
sourceand return the basename of the generated file (which lives inout_dir). -
#target_filename(source, basename = nil) ⇒ Object
The file name for
sourceunder the current options.
Constructor Details
#initialize(opts = {}) ⇒ Renderer
opts is a plain Hash with symbol keys:
:format, :scale, :width, :theme, :view, :background, :font_family,
:force, :all_views, :size, :orientation, :margin,
:node, :package_dir, :out_dir, :cache
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 40 def initialize(opts = {}) @format = normalize_format(opts[:format]) @scale = normalize_scale(opts[:scale]) @width = normalize_width(opts[:width]) @theme = normalize_theme(opts[:theme]) @view = presence(opts[:view]) @background = normalize_background(opts[:background]) @font_family = presence(opts[:font_family]) @force = truthy(opts[:force], false) @all_views = truthy(opts[:all_views], false) @size = normalize_size(opts[:size]) @orientation = normalize_orientation(opts[:orientation]) @margin = normalize_margin(opts[:margin]) @node = opts[:node] || 'node' @package_dir = opts[:package_dir] @out_dir = opts[:out_dir] || Dir.pwd @cache = opts.key?(:cache) ? opts[:cache] : true if @all_views && @format != 'pdf' raise Error, 'all-views needs format=pdf; an svg or png is a single image' end end |
Instance Attribute Details
#all_views ⇒ Object (readonly)
Returns the value of attribute all_views.
64 65 66 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 64 def all_views @all_views end |
#format ⇒ Object (readonly)
Returns the value of attribute format.
63 64 65 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 63 def format @format end |
#grading_fails ⇒ Object (readonly)
Returns the value of attribute grading_fails.
69 70 71 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 69 def grading_fails @grading_fails end |
#has_errors ⇒ Object (readonly)
Returns the value of attribute has_errors.
69 70 71 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 69 def has_errors @has_errors end |
#invalid_errors ⇒ Object (readonly)
Returns the value of attribute invalid_errors.
69 70 71 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 69 def invalid_errors @invalid_errors end |
#margin ⇒ Object (readonly)
Returns the value of attribute margin.
64 65 66 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 64 def margin @margin end |
#orientation ⇒ Object (readonly)
Returns the value of attribute orientation.
64 65 66 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 64 def orientation @orientation end |
#out_dir ⇒ Object (readonly)
Returns the value of attribute out_dir.
63 64 65 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 63 def out_dir @out_dir end |
#resolved_height ⇒ Object (readonly)
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
68 69 70 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 68 def resolved_height @resolved_height end |
#resolved_pages ⇒ Object (readonly)
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
68 69 70 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 68 def resolved_pages @resolved_pages end |
#resolved_theme ⇒ Object (readonly)
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
68 69 70 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 68 def resolved_theme @resolved_theme end |
#resolved_width ⇒ Object (readonly)
Populated by #render (from the Node helper's summary, or from the cache sidecar on a cache hit).
68 69 70 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 68 def resolved_width @resolved_width end |
#scale ⇒ Object (readonly)
Returns the value of attribute scale.
63 64 65 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 63 def scale @scale end |
#size ⇒ Object (readonly)
Returns the value of attribute size.
64 65 66 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 64 def size @size end |
#theme ⇒ Object (readonly)
Returns the value of attribute theme.
63 64 65 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 63 def theme @theme end |
#view ⇒ Object (readonly)
Returns the value of attribute view.
63 64 65 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 63 def view @view end |
#width ⇒ Object (readonly)
Returns the value of attribute width.
63 64 65 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 63 def width @width end |
Instance Method Details
#command_for(out_path) ⇒ Object
Assemble the node command line (exposed for testing).
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 117 def command_for(out_path) cmd = [@node, SCRIPT, '--format', @format, '--scale', sprintf('%g', @scale), '--out', out_path] cmd.push('--width', @width.to_s) if @width cmd.push('--theme', @theme) if @theme cmd.push('--view', @view) if @view case @background when :transparent then cmd << '--transparent' when nil then nil else cmd.push('--background', @background) end cmd.push('--font-family', @font_family) if @font_family cmd << '--force' if @force cmd << '--all-views' if @all_views cmd.push('--size', @size) if @size cmd.push('--orientation', @orientation) if @orientation cmd.push('--margin', @margin.to_s) if @margin cmd.push('--package-dir', @package_dir) if @package_dir cmd end |
#render(source, basename = nil) ⇒ Object
Render source and return the basename of the generated file (which
lives in out_dir). Pass basename (without extension) to get a
stable, human-chosen file name instead of a content hash.
Raises Renderer::Error on failure (a study with errors and no
force, an unknown view, a rendering crash, ...).
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 76 def render(source, basename = nil) FileUtils.mkdir_p(@out_dir) filename = target_filename(source, basename) path = File.join(@out_dir, filename) key = digest(source) if @cache && ( = (path, key)) () return filename end cmd = command_for(path) stdout, stderr, status = Open3.capture3(*cmd, stdin_data: source, binmode: true) unless status.success? detail = stderr.to_s.strip detail = stdout.to_s.strip if detail.empty? raise Error, "PTC rendering failed (#{@format}): #{detail}" end unless File.file?(path) raise Error, "PTC renderer produced no output at #{path}: #{stderr.to_s.strip}" end warn_lines(stderr) = parse_summary(stdout) () (path, key, ) if @cache filename end |
#target_filename(source, basename = nil) ⇒ Object
The file name for source under the current options. Uses
basename verbatim when given, otherwise a content-addressed name.
108 109 110 111 112 113 114 |
# File 'lib/asciidoctor/ptc/renderer.rb', line 108 def target_filename(source, basename = nil) if basename && !basename.to_s.strip.empty? "#{sanitize_basename(basename)}.#{@format}" else "ptc-#{digest(source)}.#{@format}" end end |