module Clayoven::Claytext

The claytext paragraph processor

The actual transformation rules are the constants in Clayoven::Claytext::Transforms.

Constants

HTMLESCAPE_RULES

We only HTML escape very few things, for simplicity

Public Class Methods

fenced_transforms!(paragraphs) click to toggle source

Perform the transforms in Clayoven::Claytext::Transforms::FENCED on Paragraph entries in-place

# File lib/clayoven/claytext.rb, line 55
def self.fenced_transforms!(paragraphs)
  # For MathJax, exercises, codeblocks, and other fenced content
  Transforms::FENCED.each do |delims, lambda_cb|
    blocks = merge_fenced! paragraphs, delims[0], delims[1]
    blocks.each { |blk| lambda_cb.call blk.block, blk.fc, blk.lc }
  end
end
line_transforms!(paragraphs) click to toggle source

Perform the transforms in Clayoven::Claytext::Transforms::LINE on Paragraph entries in-place

# File lib/clayoven/claytext.rb, line 64
def self.line_transforms!(paragraphs)
  paragraphs.filter { |p| p.type == :plain }.each do |p|
    # Apply the Transforms::LINE on all the paragraphs
    Transforms::LINE.each do |regex, lambda_cb|
      lambda_cb.call(p, regex) if p.split("\n").all?(regex)
    end
  end
end
merge_fenced!(paragraphs, fregex, lregex) click to toggle source

Merge Paragraph entries with fences marked by the start regex fregex and end regex lregex

# File lib/clayoven/claytext.rb, line 30
def self.merge_fenced!(paragraphs, fregex, lregex)
  mb = Struct.new(:block, :fc, :lc)
  matched_blocks = []
  paragraphs.each_with_index do |p, pidx|
    pmatch = fregex.match p
    next unless pmatch

    paragraphs[pidx..].each_with_index do |q, idx|
      qmatch = lregex.match q
      next unless qmatch

      # Replace paragraph p with all the paragraphs from pidx to pidx + idx, after stripping out the delims.
      # The final result, the "fenced paragraph" sits at pidx.
      p.replace(Util.slice_strip_fences!(paragraphs, pidx, idx + 1))
      matched_blocks << mb.new(p, pmatch, qmatch)

      # The final result is at pidx; throw out all the idx paragraphs, starting at pidx + 1
      paragraphs.slice! pidx + 1, idx
      break
    end
  end
  matched_blocks
end
process(body) click to toggle source

Takes a body of claytext (String), breaks it up into paragraphs, and applies various rules on it.

Returns an Array of Paragraph

# File lib/clayoven/claytext.rb, line 93
def self.process(body)
  # Split the body into Paragraphs
  paragraphs = body.split("\n\n").map { |p| Paragraph.new p.rstrip }

  # Merge paragraphs along fences, and do the transforms
  fenced_transforms! paragraphs
  line_transforms! paragraphs

  # At the end of both sets of transforms, htmlescape everything but `:mathjax`
  paragraphs.reject { |p| p.type == :mathjax }.each do |p|
    p.gsub!(/[<>&]/, HTMLESCAPE_RULES)
  end

  # Insert HTML breaks in :plain paragraphs
  paragraphs.filter { |p| p.type == :plain }.each { |p| p.gsub!(/\n/, "<br/>\n") }

  # Process `...` and `[...](...)`
  process_inline_markdown paragraphs
end
process_inline_markdown(paragraphs) click to toggle source

Insert <{mark, a}> in certain kinds of Paragraph#type

# File lib/clayoven/claytext.rb, line 81
def self.process_inline_markdown(paragraphs)
  paragraphs.select { |p| %i[plain olitems exercise footer blurb].count(p.type).positive? }.each do |p|
    p.gsub!(/`([^`]+)`/, '<mark>\1</mark>')
    p.gsub!(/\[([^\]]+)\]\(([^)]+)\)/, '<a href="\2">\1</a>')
  end
  paragraphs
end