Class: Mayu::VDOM::VTree

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Includes:
Interfaces::VTree
Defined in:
lib/mayu/vdom/vtree.rb

Defined Under Namespace

Classes: Updater

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(session:, task: Async::Task.current) ⇒ VTree

Returns a new instance of VTree.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/mayu/vdom/vtree.rb', line 174

def initialize(session:, task: Async::Task.current)
  @root = T.let(nil, T.nilable(VNode))
  @id_generator = T.let(IdGenerator.new, IdGenerator)
  @session = T.let(session, Session)

  @handlers = T.let({}, T::Hash[String, Component::HandlerRef])
  @handler_counts = T.let(RefCounter.new, RefCounter[String])

  @update_queue = T.let(Async::Queue.new, Async::Queue)

  @update_semaphore =
    T.let(Async::Semaphore.new(parent: task), Async::Semaphore)

  @assets = T.let(Set.new, T::Set[String])
end

Instance Attribute Details

#assetsObject (readonly)

Returns the value of attribute assets.



171
172
173
# File 'lib/mayu/vdom/vtree.rb', line 171

def assets
  @assets
end

#rootObject (readonly)

Returns the value of attribute root.



168
169
170
# File 'lib/mayu/vdom/vtree.rb', line 168

def root
  @root
end

#sessionObject (readonly)

Returns the value of attribute session.



163
164
165
# File 'lib/mayu/vdom/vtree.rb', line 163

def session
  @session
end

#update_queueObject (readonly)

Returns the value of attribute update_queue.



166
167
168
# File 'lib/mayu/vdom/vtree.rb', line 166

def update_queue
  @update_queue
end

Instance Method Details

#action(type, payload) ⇒ Object



280
281
282
# File 'lib/mayu/vdom/vtree.rb', line 280

def action(type, payload)
  @update_queue.enqueue([:action, { type:, payload: }])
end

#cleanup_unused_handlers!Object



314
315
316
317
318
319
320
321
# File 'lib/mayu/vdom/vtree.rb', line 314

def cleanup_unused_handlers!
  @handlers.delete_if do |id, handler|
    if @handler_counts.count(id).zero?
      Console.logger.warn(self, "Removing handler #{id}")
      true
    end
  end
end

#enqueue_update!(vnode) ⇒ Object



262
263
264
265
266
267
268
269
# File 'lib/mayu/vdom/vtree.rb', line 262

def enqueue_update!(vnode)
  component = vnode.component
  return unless component
  return if component.dirty?

  component.dirty!
  @update_queue.enqueue(vnode)
end

#handle_callback(handler_id, payload = {}) ⇒ Object



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/mayu/vdom/vtree.rb', line 225

def handle_callback(handler_id, payload = {})
  case handler_id
  when "ping"
    @update_queue.enqueue([:pong, payload[:timestamp]])
    return
  when "navigate"
    navigate(payload[:path])
    return
  end

  @handlers
    .fetch(handler_id) do
      raise KeyError, "Handler not found: #{handler_id}"
    end
    .call(payload)
rescue => e
  puts e.message
  puts e.backtrace
  error = {
    type: e.class.name,
    message: e.message,
    backtrace: e.backtrace
  }
  @update_queue.enqueue([:exception, error])
end

#id_treeObject



257
258
259
# File 'lib/mayu/vdom/vtree.rb', line 257

def id_tree
  @root&.id_tree
end

#marshal_dumpObject



191
192
193
# File 'lib/mayu/vdom/vtree.rb', line 191

def marshal_dump
  [@root, @id_generator, @assets]
end

#marshal_load(a) ⇒ Object



196
197
198
199
200
201
202
203
204
# File 'lib/mayu/vdom/vtree.rb', line 196

def marshal_load(a)
  @root, @id_generator, @assets = a
  @handlers = {}
  @handler_counts = RefCounter.new
  @update_queue = Async::Queue.new
  @update_semaphore = Async::Semaphore.new
  @assets = Set.new
  @root.instance_variable_set(:@vtree, self)
end


275
276
277
# File 'lib/mayu/vdom/vtree.rb', line 275

def navigate(path)
  @update_queue.enqueue([:navigate, path])
end

#next_id!Object



272
# File 'lib/mayu/vdom/vtree.rb', line 272

def next_id! = @id_generator.next!

#patch(ctx, vnode, descriptor, lifecycles:) ⇒ Object



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/mayu/vdom/vtree.rb', line 292

def patch(ctx, vnode, descriptor, lifecycles:)
  unless vnode
    return nil unless descriptor

    vnode = init_vnode(ctx, descriptor, lifecycles:)
    ctx.insert(vnode)
    return vnode
  end

  return remove_vnode(ctx, vnode, lifecycles:) unless descriptor

  if vnode.descriptor.same?(descriptor)
    patch_vnode(ctx, vnode, descriptor, lifecycles:)
  else
    remove_vnode(ctx, vnode, lifecycles:)
    vnode = init_vnode(ctx, descriptor, lifecycles:)
    ctx.insert(vnode)
    return vnode
  end
end

#render(descriptor, ctx: UpdateContext.new, lifecycles: true) ⇒ Object



213
214
215
216
217
# File 'lib/mayu/vdom/vtree.rb', line 213

def render(descriptor, ctx: UpdateContext.new, lifecycles: true)
  start_at = Time.now
  @root = patch(ctx, @root, descriptor, lifecycles:)
  ctx
end

#replace_root(descriptor) ⇒ Object



220
221
222
# File 'lib/mayu/vdom/vtree.rb', line 220

def replace_root(descriptor)
  @update_queue.enqueue([:replace_root, descriptor])
end

#to_htmlObject



252
253
254
# File 'lib/mayu/vdom/vtree.rb', line 252

def to_html
  @root&.to_html.to_s
end