Class: TranslationDiff::Passage::Scanner

Inherits:
Ox::Sax
  • Object
show all
Defined in:
lib/translation_diff/passage.rb

Overview

Ox reports a byte position for every construct it sees; recording those is what lets rendering slice the source.

Defined Under Namespace

Classes: Mark

Constant Summary collapse

PROTECTED =

Providers honour this class themselves under the HTML mode this gem sends, so the element must reach them whole.

"notranslate".freeze
OPENING_ANGLE =
"<".ord

Instance Method Summary collapse

Constructor Details

#initialize(source, opaque_elements:) ⇒ Scanner

Ox reports positions only to a handler that already has the ivar, so @pos exists before parsing starts. opaque_elements is a caller-supplied set of element names, so it is normalised here rather than trusted as given.



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/translation_diff/passage.rb', line 46

def initialize(source, opaque_elements:)
  super()
  @source = source
  @opaque = opaque_elements.map { |element| element.to_s.downcase.to_sym }
  @pos = 0
  @marks = []
  @protected_depth = 0
  @opaque_depth = 0
  @opaque_bump = false
  @pending = nil
end

Instance Method Details

#attr(name, value) ⇒ Object

Attributes arrive straight after their own start element, so @pending is that element and never another. A protected element's own end_element takes the protected branch and never reaches the opaque decrement, so an opaque_depth this element raised has to be given back here or it would outlive the element that raised it.



78
79
80
81
82
83
84
85
# File 'lib/translation_diff/passage.rb', line 78

def attr(name, value)
  return unless @pending && protection?(name, value)

  @pending.prose = true
  @opaque_depth -= 1 if @opaque_bump
  @protected_depth = 1
  @pending = nil
end

#cdata(_content) ⇒ Object



98
# File 'lib/translation_diff/passage.rb', line 98

def cdata(_content) = record(prose: false)

#comment(_content) ⇒ Object



96
# File 'lib/translation_diff/passage.rb', line 96

def comment(_content) = record(prose: false)

#doctype(_content) ⇒ Object



100
# File 'lib/translation_diff/passage.rb', line 100

def doctype(_content) = record(prose: false)

#end_element(_name) ⇒ Object



87
88
89
90
91
92
# File 'lib/translation_diff/passage.rb', line 87

def end_element(_name)
  return @protected_depth -= 1 if @protected_depth.positive?

  @opaque_depth -= 1 if @opaque_depth.positive?
  record(prose: false)
end

#instruct(_target) ⇒ Object



102
# File 'lib/translation_diff/passage.rb', line 102

def instruct(_target) = record(prose: false)

#runs ⇒ Object

Triples of [first byte, last byte + 1, prose?], contiguous, covering the source exactly once.



59
60
61
62
# File 'lib/translation_diff/passage.rb', line 59

def runs
  Ox.sax_html(self, StringIO.new(@source))
  merge(bounds)
end

#start_element(name) ⇒ Object

Protection beats opacity on purpose: a caller wrapping a subtree asked for it to be passed through as it is. that increment if the element turns out to be protected -- its own end_element never gets the chance to.



67
68
69
70
71
72
73
# File 'lib/translation_diff/passage.rb', line 67

def start_element(name)
  return @protected_depth += 1 if @protected_depth.positive?

  @opaque_bump = @opaque_depth.positive? || @opaque.include?(name.to_s.downcase.to_sym)
  @opaque_depth += 1 if @opaque_bump
  @pending = mark(prose: false)
end

#value(_value) ⇒ Object



94
# File 'lib/translation_diff/passage.rb', line 94

def value(_value) = record(prose: @opaque_depth.zero?)