Class: MaquinaStream::Block

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

Overview

One top-level block of a message: the slice of raw markdown it came from, the HTML it rendered to, and whether it is safe to freeze.

The id is derived from the index and never from the content. Idiomorph keys on id, so a content-derived id turns every edit into a delete-and-recreate, which loses scroll position, animation state and anything the client owns.

Blocks come from Document. Building one by hand is possible but rarely useful: the id and digest a repair needs are stamped on during that split. Instances are immutable — #seal returns a new Block rather than mutating.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(index:, markdown:, html:, line_range:, sid: nil, sealed: false, digest: nil) ⇒ Block

Builds a block. Document does this; a host normally reads blocks rather than constructing them.



38
39
40
41
42
43
44
45
46
# File 'lib/maquina_stream/block.rb', line 38

def initialize(index:, markdown:, html:, line_range:, sid: nil, sealed: false, digest: nil)
  @index = index
  @markdown = markdown
  @html = html
  @line_range = line_range
  @sid = sid
  @sealed = sealed
  @digest = digest
end

Instance Attribute Details

#html ⇒ Object (readonly)

The rendered HTML for this block alone, including its own element and the id, data-ms-block and data-ms-block-digest attributes.



26
27
28
# File 'lib/maquina_stream/block.rb', line 26

def html
  @html
end

#index ⇒ Object (readonly)

This block's position in the document, zero-based. The id is derived from it.



19
20
21
# File 'lib/maquina_stream/block.rb', line 19

def index
  @index
end

#line_range ⇒ Object (readonly)

The Range of 1-based source lines this block covers. Coverage has gaps — an HTML block reports no source position at all — so a block with no range of its own inherits the lines between its neighbours.



31
32
33
# File 'lib/maquina_stream/block.rb', line 31

def line_range
  @line_range
end

#markdown ⇒ Object (readonly)

The slice of raw markdown this block was rendered from.



22
23
24
# File 'lib/maquina_stream/block.rb', line 22

def markdown
  @markdown
end

#sid ⇒ Object (readonly)

The stream id this block belongs to, or nil for an anonymous render.



34
35
36
# File 'lib/maquina_stream/block.rb', line 34

def sid
  @sid
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Two blocks are equal when they hold the same index and the same HTML. Sealing is deliberately not part of it: a block that sealed between two frames is the same block, and the seal is a decision about it rather than a property of it.



91
92
93
# File 'lib/maquina_stream/block.rb', line 91

def ==(other)
  other.is_a?(Block) && other.index == index && other.html == html
end

#digest ⇒ Object

Digest of the block's rendered CONTENT, not of the source and not of the whole element.

The manifest compares what the browser actually has, so two different sources that render alike need no repair between them. Element-level attributes are excluded on purpose: a block gains data-ms-block-state when it seals and loses data-ms-caret when the tail moves past it, and neither changes what the block says. Digesting them would make every block in every message fetch itself once, for nothing.



70
71
72
# File 'lib/maquina_stream/block.rb', line 70

def digest
  @digest ||= Digest::SHA256.hexdigest(html.to_s)[0, 16]
end

#hash ⇒ Object

Hashed on the same two fields #== compares.



97
# File 'lib/maquina_stream/block.rb', line 97

def hash = [index, html].hash

#id ⇒ Object

The DOM id, ms-<sid>-b<index>. Index-derived, never content-derived: idiomorph keys on it.



50
51
52
# File 'lib/maquina_stream/block.rb', line 50

def id
  sid ? "ms-#{sid}-b#{index}" : "ms-b#{index}"
end

#open? ⇒ Boolean

Whether this block can still change, and can therefore still be patched.

Returns:

  • (Boolean)


59
# File 'lib/maquina_stream/block.rb', line 59

def open? = !sealed?

#seal ⇒ Object

A copy of this block, sealed. Returns a new Block; the receiver is unchanged.



76
77
78
79
80
81
# File 'lib/maquina_stream/block.rb', line 76

def seal
  self.class.new(
    index: index, markdown: markdown, html: html,
    line_range: line_range, sid: sid, sealed: true, digest: digest
  )
end

#sealed? ⇒ Boolean

Whether this block is frozen — far enough behind the tail that nothing can reinterpret it, and therefore never re-broadcast.

Returns:

  • (Boolean)


56
# File 'lib/maquina_stream/block.rb', line 56

def sealed? = @sealed

#to_manifest_entry ⇒ Object

[id, digest] — one row of a Manifest, and the unit the client diffs its own DOM against.



85
# File 'lib/maquina_stream/block.rb', line 85

def to_manifest_entry = [id, digest]