Class: MaquinaStream::Document

Inherits:
Object
  • Object
show all
Defined in:
lib/maquina_stream/document.rb

Overview

Splits a rendered message into top-level blocks, and decides which of them are safe to freeze.

document = MaquinaStream::Document.new(markdown, config: config, sid: "m8f21")
document.blocks          # every top-level block, in order
document.sealed_blocks   # frozen, never re-sent
document.open_block      # the tail, patched on every frame

The whole buffer is rendered once and then sliced. Blocks are never rendered in isolation: a block that mentions [docs] needs the link reference definition that lives at the bottom of the message, and rendering it alone silently loses it.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(markdown, config: MaquinaStream.config, sid: nil, mode: :streaming) ⇒ Document

Builds a document over one markdown buffer.

sid: is the record's maquina_stream_id. Pass it: block ids are built from it, and a document rendered without one produces ids (ms-b0, ms-b1) that collide the moment two messages share a page.

Nothing is rendered until #blocks or #html is called.



39
40
41
42
43
44
# File 'lib/maquina_stream/document.rb', line 39

def initialize(markdown, config: MaquinaStream.config, sid: nil, mode: :streaming)
  @markdown = markdown.to_s
  @config = config
  @sid = sid
  @mode = mode
end

Instance Attribute Details

#config ⇒ Object (readonly)

The Configuration it reads — seal_lag in particular.



23
24
25
# File 'lib/maquina_stream/document.rb', line 23

def config
  @config
end

#markdown ⇒ Object (readonly)

The raw markdown this document was built from.



20
21
22
# File 'lib/maquina_stream/document.rb', line 20

def markdown
  @markdown
end

#mode ⇒ Object (readonly)

The render mode passed through to Renderer, one of Renderer::MODES.



30
31
32
# File 'lib/maquina_stream/document.rb', line 30

def mode
  @mode
end

#sid ⇒ Object (readonly)

The stream id every block id is prefixed with, or nil for an anonymous render.



27
28
29
# File 'lib/maquina_stream/document.rb', line 27

def sid
  @sid
end

Instance Method Details

#blocks ⇒ Object

Every top-level Block, in document order, each already stamped with its id and digest. Memoized: the whole buffer is rendered once, on the first call.



49
50
51
# File 'lib/maquina_stream/document.rb', line 49

def blocks
  @blocks ||= build_blocks
end

#html ⇒ Object

The whole document as one rendered HTML string, before it is sliced into blocks. Memoized.



87
88
89
# File 'lib/maquina_stream/document.rb', line 87

def html
  @html ||= Renderer.call(markdown, mode: mode, config: config)
end

#manifest_entries ⇒ Object

[[id, digest], …] for the sealed blocks. What Manifest is built from.



92
93
94
# File 'lib/maquina_stream/document.rb', line 92

def manifest_entries
  sealed_blocks.map(&:to_manifest_entry)
end

#open_block ⇒ Object

The last block — the tail the model is currently writing into.



81
82
83
# File 'lib/maquina_stream/document.rb', line 81

def open_block
  blocks.last
end

#seal_pointer ⇒ Object

How far sealing reached, as an index into #blocks. Sealing is a prefix, so this is both the count of sealed blocks and the position of the first unsealed one.



76
77
78
# File 'lib/maquina_stream/document.rb', line 76

def seal_pointer
  @seal_pointer ||= blocks.count(&:sealed?)
end

#sealed_blocks ⇒ Object

Sealed blocks trail the tail by config.seal_lag. Markdown reinterprets retroactively - a paragraph becomes a heading when its underline arrives, a table's delimiter row turns the line above into a header - so a block is only safe to freeze once enough later blocks exist that nothing can reach back into it.

The lag is not the whole story. A link reference definition resolves links in blocks arbitrarily far above it, so no fixed lag makes a block with an unresolved reference safe. The pointer stops there instead, and moves on once the definition arrives.



63
64
65
# File 'lib/maquina_stream/document.rb', line 63

def sealed_blocks
  blocks.first(seal_pointer)
end

#unsealed_blocks ⇒ Object

The blocks behind the seal pointer: still able to change, and therefore still eligible for a patch on the next frame.



69
70
71
# File 'lib/maquina_stream/document.rb', line 69

def unsealed_blocks
  blocks.drop(seal_pointer)
end