Module: Coradoc::AsciiDoc::Parser::Inline
- Defined in:
- lib/coradoc/asciidoc/parser/inline.rb
Constant Summary collapse
- INLINE_RULE_ORDER =
Priority-ordered registry of inline rules. The ORDER IS LOAD-BEARING: typographic_quote MUST come before monospace_constrained (Bug 14); each unconstrained rule MUST come before its constrained sibling (
before``,**before*,__before_`). Adding a new inline rule = appending one symbol here (OCP). %i[ typographic_quote bold_unconstrained bold_constrained span_unconstrained span_constrained italic_unconstrained italic_constrained highlight_unconstrained highlight_constrained monospace_unconstrained monospace_constrained superscript subscript attribute_reference escaped_xref cross_reference term_inline term_inline2 footnote stem link inline_image inline_passthrough underline small hard_line_break ].freeze
Instance Method Summary collapse
- #attribute_reference ⇒ Object
- #bold_constrained ⇒ Object
- #bold_unconstrained ⇒ Object
-
#constrained_mark(marker, reject_paragraph_break: false, content: nil) ⇒ Object
── Constrained / unconstrained mark builders ──.
-
#constrained_span_content(marker) ⇒ Object
Content model for a constrained inline span (
`…`,*…*,_…_,#…#). - #default_constrained_content(marker) ⇒ Object
- #hard_line_break ⇒ Object
-
#hard_line_break_marker? ⇒ Boolean
AsciiDoc hard line break: a space followed by
+at end of line, or a backslash at end of line. - #highlight_constrained ⇒ Object
- #highlight_unconstrained ⇒ Object
- #inline ⇒ Object
- #inline_chars? ⇒ Boolean
- #inline_image ⇒ Object
- #inline_passthrough ⇒ Object
-
#inline_passthrough_macro ⇒ Object
pass:[raw]macro form. -
#inline_passthrough_triple_plus ⇒ Object
Triple-plus inline passthrough:
+++raw content+++. - #italic_constrained ⇒ Object
- #italic_unconstrained ⇒ Object
- #link ⇒ Object
- #monospace_constrained ⇒ Object
- #monospace_unconstrained ⇒ Object
- #small ⇒ Object
- #span ⇒ Object
- #span_constrained ⇒ Object
- #span_unconstrained ⇒ Object
- #subscript ⇒ Object
- #superscript ⇒ Object
- #text_any ⇒ Object
- #text_formatted ⇒ Object
- #text_unformatted ⇒ Object
-
#typographic_quote ⇒ Object
Typographic quote patterns are owned by the shared TypographicQuotes module so both the parser and the transformer reference the same source of truth without one layer reaching across the other.
- #unconstrained_mark(marker) ⇒ Object
- #underline ⇒ Object
Instance Method Details
#attribute_reference ⇒ Object
21 22 23 24 25 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 21 def attribute_reference str('{').present? >> str('{') >> match('[a-zA-Z0-9_-]').repeat(1).as(:attribute_reference) >> str('}') end |
#bold_constrained ⇒ Object
69 70 71 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 69 def bold_constrained constrained_mark('*', reject_paragraph_break: true).as(:bold_constrained) end |
#bold_unconstrained ⇒ Object
73 74 75 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 73 def bold_unconstrained unconstrained_mark('*').as(:bold_unconstrained) end |
#constrained_mark(marker, reject_paragraph_break: false, content: nil) ⇒ Object
── Constrained / unconstrained mark builders ──
Single source of truth for the four constrained + four unconstrained inline mark rules. Before this extraction each rule hand-rolled the same open → content → close → lookahead shape with subtly different guards (presence checks, newline exclusions, inner-marker allowances). Now each rule is a 1-line wrapper over one of two parameterised builders.
The constrained builder adds a marker.absent? guard on both
ends so single-marker constrained never matches when a
double-marker unconstrained is intended (e.g. * defers to
**). The alternation order in inline handles this too,
but the guard is belt-and-suspenders — it keeps each rule
self-contained for unit testing.
The unconstrained builder allows newlines in the content
(Asciidoctor's behaviour for __, **, ##, `` — a
mark can span line breaks). This was Bug 15B's fix scope;
highlight_unconstrained was previously inconsistent (excluded
newlines). All four are now uniform.
49 50 51 52 53 54 55 56 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 49 def constrained_mark(marker, reject_paragraph_break: false, content: nil) open_guard = str(marker) >> str(marker).absent? content_rule = content || default_constrained_content(marker) close_guard = str(marker) >> str(marker).absent? sequence = open_guard >> content_rule >> close_guard sequence >>= str("\n\n").absent? if reject_paragraph_break sequence end |
#constrained_span_content(marker) ⇒ Object
Content model for a constrained inline span (`…`, *…*,
_…_, #…#). Allows the corresponding unconstrained marker
pair ( ``, **, __, ##) to appear inside the content
rather than terminating the span at the first marker character.
Asciidoctor treats the contents of a constrained span as an
inline literal — nested constrained markers do not close the
span. Without this allowance, `<<\`\`x\`\`>>` fails to
match as a single monospace span: the parser sees the inner
`` as a failed single-backtick close attempt, backtracks
out of monospace_constrained, and the <<…>> payload then
fires the cross_reference rule with the backticks glued
onto the target.
Single source of truth for every constrained rule's content model — adding a new constrained marker reuses this helper rather than re-spelling the alternation (DRY).
288 289 290 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 288 def constrained_span_content(marker) (match("[^#{marker}\n]") | str(marker * 2)).repeat(1) end |
#default_constrained_content(marker) ⇒ Object
58 59 60 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 58 def default_constrained_content(marker) match("[^#{marker}\n]").repeat(1).as(:text).repeat(1, 1) end |
#hard_line_break ⇒ Object
228 229 230 231 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 228 def hard_line_break ((str(' +') >> str("\n")) | (str('\\') >> str("\n"))).as(:hard_line_break) end |
#hard_line_break_marker? ⇒ Boolean
AsciiDoc hard line break: a space followed by + at end of line,
or a backslash at end of line. Both forms render as <br> inside
the enclosing paragraph/verse. Recognised ahead of text_unformatted
so the marker isn't swallowed as plain text.
223 224 225 226 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 223 def hard_line_break_marker? (str(' +') >> str("\n")).present? | (str('\\') >> str("\n")).present? end |
#highlight_constrained ⇒ Object
101 102 103 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 101 def highlight_constrained constrained_mark('#').as(:highlight_constrained) end |
#highlight_unconstrained ⇒ Object
105 106 107 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 105 def highlight_unconstrained unconstrained_mark('#').as(:highlight_unconstrained) end |
#inline ⇒ Object
256 257 258 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 256 def inline INLINE_RULE_ORDER.map { |name| public_send(name) }.reduce(:|) end |
#inline_chars? ⇒ Boolean
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 203 def inline_chars? match('[\[*#_{<^~`]').present? | typographic_quote.present? | str('http').present? | str('https').present? | str('link:').present? | str('image:').present? | str('+++').present? | str('pass:').present? | term_type.present? | str('footnote').present? | stem_type.present? | str('\\<<').present? | hard_line_break_marker? end |
#inline_image ⇒ Object
151 152 153 154 155 156 157 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 151 def inline_image (str('image:').present? >> str('image:') >> str(':').absent? >> match('[A-Za-z0-9_.\\-:/&?=+,%#~;]+').repeat(1).as(:path) >> attribute_list(:attribute_list).maybe ).as(:inline_image) end |
#inline_passthrough ⇒ Object
183 184 185 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 183 def inline_passthrough inline_passthrough_triple_plus | inline_passthrough_macro end |
#inline_passthrough_macro ⇒ Object
pass:[raw] macro form. Equivalent semantic to triple-plus:
the bracket payload survives all substitutions verbatim. Common
use is inside monospace spans to keep characters like < from
being re-interpreted as xref markers. The optional subs segment
(pass:quotes[...]) is consumed but currently ignored — the
payload is always passed through raw.
175 176 177 178 179 180 181 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 175 def inline_passthrough_macro (str('pass:').present? >> str('pass:') >> match('[a-zA-Z,+]').repeat(0) >> str('[') >> (str(']]').absent? >> match('[^\]\n]')).repeat(1).as(:raw) >> str(']') ).as(:inline_passthrough) end |
#inline_passthrough_triple_plus ⇒ Object
Triple-plus inline passthrough: +++raw content+++. The content
passes through all substitutions verbatim. Common use is to embed
raw HTML in AsciiDoc documents.
162 163 164 165 166 167 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 162 def inline_passthrough_triple_plus (str('+++') >> (str('+++').absent? >> match('[^\n]')).repeat(1).as(:raw) >> str('+++') ).as(:inline_passthrough) end |
#italic_constrained ⇒ Object
93 94 95 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 93 def italic_constrained constrained_mark('_').as(:italic_constrained) end |
#italic_unconstrained ⇒ Object
97 98 99 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 97 def italic_unconstrained unconstrained_mark('_').as(:italic_unconstrained) end |
#link ⇒ Object
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 140 def link ((str('http').present? | str('https').present? | str('ftp').present?) >> match('[A-Za-z0-9_.\\-:/&?=+,%#~;]+').repeat(1).as(:path) >> (str('[') >> match('[^\\]]').repeat(1).as(:text) >> str(']')).maybe ).as(:link) | (str('link:').present? >> str('link:') >> match('[A-Za-z0-9_.\\-:/&?=+,%#~;]+').repeat(1).as(:path) >> (str('[') >> match('[^\\]]').repeat(1).as(:text) >> str(']')).maybe ).as(:link) end |
#monospace_constrained ⇒ Object
109 110 111 112 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 109 def monospace_constrained content = constrained_span_content('`').as(:text).repeat(1, 1) constrained_mark('`', content: content).as(:monospace_constrained) end |
#monospace_unconstrained ⇒ Object
114 115 116 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 114 def monospace_unconstrained unconstrained_mark('`').as(:monospace_unconstrained) end |
#small ⇒ Object
195 196 197 198 199 200 201 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 195 def small (attribute_list >> match('\\[.small\\]').as(:role) >> str('#') >> match('[^#\n]').repeat(1).as(:text) >> str('#') ).as(:small) end |
#span ⇒ Object
132 133 134 135 136 137 138 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 132 def span attribute_list >> (str('#') >> match('[^#\n]').repeat(1).as(:text) >> str('#') >> str('#').absent? ).as(:span) end |
#span_constrained ⇒ Object
77 78 79 80 81 82 83 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 77 def span_constrained (attribute_list >> str('#') >> match('[^#\n]').repeat(1).as(:text) >> str('#') >> str('#').absent? ).as(:span_constrained) end |
#span_unconstrained ⇒ Object
85 86 87 88 89 90 91 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 85 def span_unconstrained (attribute_list >> str('##') >> match('[^#\n]').repeat(1).as(:text) >> str('##') ).as(:span_unconstrained) end |
#subscript ⇒ Object
125 126 127 128 129 130 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 125 def subscript (str('~') >> match('[^~\n]').repeat(1).as(:text).repeat(1, 1) >> str('~') ).as(:subscript) end |
#superscript ⇒ Object
118 119 120 121 122 123 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 118 def superscript (str('^') >> match('[^^\n]').repeat(1).as(:text).repeat(1, 1) >> str('^') ).as(:superscript) end |
#text_any ⇒ Object
296 297 298 299 300 301 302 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 296 def text_any (text_formatted | text_unformatted.as(:text) ).repeat(2) | text_formatted.repeat(1, 1) | text_unformatted end |
#text_formatted ⇒ Object
292 293 294 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 292 def text_formatted (inline_chars? >> inline) end |
#text_unformatted ⇒ Object
260 261 262 263 264 265 266 267 268 269 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 260 def text_unformatted # `str('\\<<').absent?` stops text from consuming the backslash of # an escaped xref (`\<<`). Without this guard, the `\` is taken as # plain text, the `<<` re-enters cross_reference, and the literal # escape is destroyed. (str('\\<<').absent? >> inline.absent? >> match("[^\n]") ).repeat(1) end |
#typographic_quote ⇒ Object
Typographic quote patterns are owned by the shared TypographicQuotes module so both the parser and the transformer reference the same source of truth without one layer reaching across the other.
12 13 14 15 16 17 18 19 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 12 def typographic_quote patterns = AsciiDoc::TypographicQuotes::PATTERNS combined = patterns.reduce(nil) do |acc, pat| atom = str(pat) acc ? (acc | atom) : atom end combined.as(:typographic_quote) end |
#unconstrained_mark(marker) ⇒ Object
62 63 64 65 66 67 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 62 def unconstrained_mark(marker) double = marker * 2 str(double) >> match("[^#{marker}]").repeat(1).as(:text).repeat(1, 1) >> str(double) end |
#underline ⇒ Object
187 188 189 190 191 192 193 |
# File 'lib/coradoc/asciidoc/parser/inline.rb', line 187 def underline (attribute_list >> match('\\[.underline\\]').as(:role) >> str('#') >> match('[^#\n]').repeat(1).as(:text) >> str('#') ).as(:underline) end |